Java 立即向下投射的好处是什么?
我最近一直在看很多代码(为了我自己的利益,因为我还在学习编程),我注意到一些Java项目(来自那些看起来很受尊敬的程序员),其中他们使用某种即时向下转换 我实际上有多个示例,但这里有一个是我直接从代码中提取的:Java 立即向下投射的好处是什么?,java,coding-style,Java,Coding Style,我最近一直在看很多代码(为了我自己的利益,因为我还在学习编程),我注意到一些Java项目(来自那些看起来很受尊敬的程序员),其中他们使用某种即时向下转换 我实际上有多个示例,但这里有一个是我直接从代码中提取的: public Set<Coordinates> neighboringCoordinates() { HashSet<Coordinates> neighbors = new HashSet<Coordinates>(); neighb
public Set<Coordinates> neighboringCoordinates() {
HashSet<Coordinates> neighbors = new HashSet<Coordinates>();
neighbors.add(getNorthWest());
neighbors.add(getNorth());
neighbors.add(getNorthEast());
neighbors.add(getWest());
neighbors.add(getEast());
neighbors.add(getSouthEast());
neighbors.add(getSouth());
neighbors.add(getSouthWest());
return neighbors;
}
公共集邻域坐标(){
HashSet邻居=新HashSet();
add(getNorthWest());
add(getNorth());
add(getNorthEast());
add(getWest());
add(getEast());
add(getSouthwest());
add(getSouth());
add(getsoutwest());
回归邻居;
}
在同一个项目中,这里有另一个(也许更简洁)的例子:
private Set liveCellCoordinates=new HashSet();
在第一个示例中,您可以看到该方法的返回类型为Set
——但是,该特定方法始终只返回HashSet
——而不返回其他类型的Set
在第二个示例中,liveCellCoordinates
最初定义为集
,但立即变成哈希集
不仅仅是这个单一的、具体的项目,我发现在多个项目中都是这样
我很好奇这背后的逻辑是什么?是否有一些代码约定会考虑这一良好的实践?它会使程序更快或更高效吗?它有什么好处?因为现在如果他们将来更改类型,任何依赖于相邻坐标的代码都不必更新 让我们看看你有:
HashedSet<Coordinates> c = neighboringCoordinates()
HashedSet c=邻域坐标()
现在,让我们假设他们更改了代码以使用不同的set实现。你猜怎么着,你也得修改代码
但是,如果您有:
Set<Coordinates> c = neighboringCoordinates()
Set c=neightringcoordinates()
只要它们的集合仍然实现set,它们就可以在内部更改它们想要的任何内容,而不会影响您的代码
基本上,它只是为了隐藏内部细节而尽可能不具体(在合理范围内)。您的代码只关心它可以作为集合访问集合。它不在乎它是什么特定类型的集合,如果这有意义的话。因此,为什么要将代码耦合到HashedSet?在设计方法签名时,通常最好只锁定需要锁定的内容。在第一个示例中,通过仅指定该方法返回
集
(而不是哈希集
),如果发现哈希集
不是正确的数据结构,则实现者可以自由更改实现。如果该方法已声明为返回一个HashSet
,那么依赖于该对象的所有代码都是HashSet
,而不是更一般的Set
类型,也需要修改
一个现实的例子是,如果决定neightringcoordinates()
需要返回线程安全的Set
对象。如前所述,将方法的最后一行替换为:
return Collections.synchronizedSet(neighbors);
结果是,synchronizedSet()
返回的Set
对象与HashSet
的赋值不兼容。幸好该方法被声明为返回一个集
类似的考虑也适用于第二种情况。使用liveCellCoordinates
的类中的代码不需要知道任何东西,只需要知道它是一个集合
。(事实上,在第一个例子中,我希望看到:
Set<Coordinates> neighbors = new HashSet<Coordinates>();
Set neights=new HashSet();
在方法的顶部。)这很简单
在您的示例中,该方法返回Set
。从API设计师的角度来看,与返回HashSet
相比,这有一个显著的优势
如果在某个时刻,程序员决定使用
superperformancesetfordirections
,那么他可以在不更改公共API的情况下执行,如果在第一个示例中新类扩展了Set,那么该方法始终只返回HashSet是该类用户不必知道的实现细节。这使开发人员可以在需要时使用不同的实现。这里的设计原则是“总是更喜欢指定抽象类型”
Set
是抽象的;没有这样一个具体的类Set
——它是一个接口,根据定义是抽象的。该方法的契约是返回一个Set
——由开发人员选择返回哪种Set
您还应该对字段执行此操作,例如:
private List<String> names = new ArrayList<String>;
私有列表名称=新的ArrayList;
不是
private ArrayList name=new ArrayList;
稍后,您可能希望更改为使用LinkedList
——指定抽象类型允许您在不更改代码的情况下执行此操作(当然,初始化除外)。诀窍是“将代码转换为接口”
其原因是,在99.9%的情况下,您只希望来自HashSet/TreeSet/WhateverSet
的行为符合所有人实现的Set
-接口。它使您的代码更简单,而您真正需要说HashSet
的唯一原因是指定所需的集具有什么行为
正如您可能知道的,HashSet相对较快,但返回的项似乎是随机顺序的。TreeSet稍微慢一点,但按字母顺序返回项目。只要代码的行为像一个集合,它就不在乎
这使得代码更简单,更容易使用
注意,集合的典型选择是HashSet,Map是HashMap,List是ArrayList。如果你使用
private List<String> names = new ArrayList<String>;
private ArrayList<String> names = new ArrayList<String>;