我是Java的初学者。如果以下正确与错误,我会感到困惑。
第一个条件已被理解并经常使用。别人有什么用?我何时以及如何利用它们?
/* 1) */ Car car = new Car();
/* 2) */ Car car = new Vehicle();
/* 3) */ Vehicle car = new Car();
/* 4) */ Vehicle vehicle = new Vehicle();
也许您可以在答案中包含示例。
答案 0 :(得分:1)
通常,您应该仅通过要使用的最通用的接口(例如Iterable
,Collection
或List
)声明变量,然后使用特定的实现对其进行初始化(例如ArrayList
,LinkedList
或Arrays.asList()
)。
否则,您会将代码限制为该特定类型,并且在需要时将很难更改。
例如,如果您要将ArrayList
传递到void method(...)
:
// Iterable if you just need iteration, for (String s : strings):
void method(Iterable<String> strings) {
for (String s : strings) { ... }
}
// Collection if you also need .size(), .isEmpty(), or .stream():
void method(Collection<String> strings) {
if (!strings.isEmpty()) { strings.stream()... }
}
// List if you also need .get(index):
void method(List<String> strings) {
strings.get(...)
}
// Don't declare a specific list implementation
// unless you're sure you need it:
void method(ArrayList<String> strings) {
??? // You don't want to limit yourself to just ArrayList
}
另一示例将始终将变量声明为InputStream
,即使它通常是FileInputStream
或BufferedInputStream
,因为有一天您或其他人会想使用其他类型的变量的InputStream
。
答案 1 :(得分:-1)
在许多情况下,超类(或接口)描述了一个通用对象,但是子类在实现上有所不同,以使代码更高效或更易于访问。
一个很好的例子是接口List
。它有两个主要的子类AbstractList
和AbstractSequentialList
。这些提供了List
中大多数方法的实现,但是将实际的内存管理留给了它们的子类。
创建List
对象时,通常是因为我想要一个长度可变的数组,而不是因为ArrayList
的确切实现(尽管它确实指定了一些更有用的方法,您可以无法访问List
)。
这意味着我只是说
List<?> list = new ArrayList<?>();
因为我想要一个列表,但还必须指定对我的原因最有效的实现。
关于您的Vehicle
和Car
类,我说这取决于您要实现的目标。在这种情况下,如下所示指定Car
对象可能是最明智的:
Car car = new Car();
因为您是专门要求汽车的,而不仅仅是将Car
用作Vehicle
的特定实现方式。
结论:
SomeClass c = new SomeClassSuperclass();
当SomeClass
只是SomeClassSuperclass
的一种实现方式时,最有用和可读。
SomeClass c = new SomeClass();
当SomeClass
被认为是SomeClassSuperclass
的另一种类型时,是最有用和易读的,但是它仍然具有使其自身成为SomeClass
而不是{{1}的特征。 }(以现实生活中的汽车为例,您不会指向汽车并说“看,一辆很棒的车!”或“看,我有一辆新车!”,因为这些短语并不能真正给您带来太多好处有关您正在谈论的内容的信息)