Java:如何区分何时声明其自身或其父对象实例?

Java:如何区分何时声明其自身或其父对象实例?,java,Java,我是Java初学者。我不知道下面的内容是否正确 第一个条件被理解并经常使用。其他人的用途是什么?何时以及如何利用它们 /* 1) */ Car car = new Car(); /* 2) */ Car car = new Vehicle(); /* 3) */ Vehicle car = new Car(); /* 4) */ Vehicle vehicle = new Vehicle(); 也许你可以在你的答案中包括一些例子 通常,您只需通过将要使用的最通用的接口(例如Iterable、C

我是Java初学者。我不知道下面的内容是否正确

第一个条件被理解并经常使用。其他人的用途是什么?何时以及如何利用它们

/* 1) */ Car car = new Car();
/* 2) */ Car car = new Vehicle();
/* 3) */ Vehicle car = new Car();
/* 4) */ Vehicle vehicle = new Vehicle();

也许你可以在你的答案中包括一些例子

通常,您只需通过将要使用的最通用的接口(例如
Iterable
Collection
、或
List
)声明变量,并使用特定实现(例如
ArrayList
LinkedList
Arrays.asList()
)初始化它们

否则,您会将代码限制为该特定类型,并且在需要时很难进行更改

例如,如果要将
ArrayList
传递给
void方法(…)

//Iterable如果您只需要迭代,例如(字符串s:strings):
void方法(Iterable字符串){
对于(字符串s:strings){…}
}
//如果您还需要.size()、.isEmpty()或.stream(),则可以使用该集合:
void方法(集合字符串){
如果(!strings.isEmpty()){strings.stream()…}
}
//如果您还需要,请列出。获取(索引):
void方法(列出字符串){
strings.get(…)
}
//不要声明特定的列表实现
//除非你确定你需要它:
void方法(ArrayList字符串){
???//您不想将自己局限于ArrayList
}


另一个例子是总是将变量声明为
InputStream
,即使它通常是
FileInputStream
BufferedInputStream
,因为不久的将来,您或其他人会想在许多情况下使用某种其他类型的
InputStream
超类(或接口)描述一般对象,但子类在实现上有所不同,以使代码更高效或更易访问

一个很好的例子是界面
列表
。它有两个主要的子类
AbstractList
AbstractSequentialList
。它们提供了
列表
中大多数方法的实现,但将实际内存管理留给它们的子类

当我创建一个
List
对象时,通常是因为我想要一个改变长度的数组,而不是因为
ArrayList
的精确实现(尽管它确实指定了一些在
List
中无法访问的更有用的方法)。 这意味着我只是说

List<?> list = new ArrayList<?>();
因为您是专门要求一辆车,而不仅仅是将
car
用作
Vehicle
的特定实现

总之:

SomeClass c = new SomeClassSuperclass();
SomeClass
只是
SomeClassSuperclass
的一个实现时,它是最有用和可读的

SomeClass c = new SomeClass();

SomeClass
被认为是一种不同类型的
SomeClassSuperclass
时,它是最有用和可读的,但它仍然有自己的特性,使它成为
SomeClass
而不是
SomeClassSuperclass
(想想现实生活中的一辆车,你不会指着一辆车说“看,一辆很棒的车!”“看,我买了一辆新车!”,因为这些短语并没有给你提供太多关于你正在谈论的内容的信息)

可能有关联:
Car
vehicle
有什么关联?一个是扩展另一个吗?如果我理解正确(Car是vehicle的一个子类),
Car-Car=new-vehicle();
不会编译,因为车辆不是汽车,但汽车是汽车。Vehicle mVehicle=(Vehicle)new Car();//请参见始终以“m”作为前缀的变量。我已将汽车转换为汽车。这应该行得通,因为汽车始终是汽车。我从我的另一个答案复制了这一点:
SomeClass c = new SomeClassSuperclass();
SomeClass c = new SomeClass();