一行
A var = new B();
是两个独立步骤的简写。
A var; // (1) Make a variable of TYPE A.
var = new B(); // (2) Make an object of CLASS B, that from now on may be
// referred to by the variable var.
所以一个变量有一个TYPE,一个对象有一个CLASS。他们经常匹配。变量的类型通常实际上是一个类,尽管不一定。理解变量的类型和变量所引用的对象的类之间的区别很重要。
一个对象通常属于多个类。如果 B 类扩展了 A 类,这意味着 B 类的所有对象也是 A 类的对象。并且任何类的所有对象也是Object 类的对象。换句话说,当我们说一个对象是 B 时,这比说它是 A 更具体。就像我们说 Yogi 是 bear 时,这比说 Yogi 是 动物,因为所有的熊都是动物。
因此,如果 A 是 B 扩展的类,则 A 类型的变量确实可以引用 B 类的对象。但是如果你有一个 A 类型的变量,你就不能用它来做特定于 B 类型的对象的事情。例如,假设 A 类有一个名为 display() 的方法,而 B 类有一个名为explain()。编译器将允许您在类型 A 的变量上调用 display(),但不允许您调用 explain()。如果是这样,则尝试在实际上不是 B 的对象上调用 explain() 会有风险,这会失败。
因此,只要有 B 类定义的方法,您就需要一个 B 类型的变量才能调用它们。当然,你也可以使用同一个变量来调用类 A 中定义的方法。那么从某种意义上说,如果类 B 扩展类 A,那么 B 类型的变量比 A 类型的变量更强大——你可以用它做更多的事情。
所以问题来了——我为什么要写作
A var = new B();
在这个例子中,什么时候类型 B 的变量会比 var 更强大?
简短的回答是它与查看代码的人交流。它说,“是的,我知道这个变量指的是 B,但我实际上只打算使用 A 类提供的方法。这实际上对试图理解你的代码或维护它的人很有帮助。
在某些情况下,它可以对涉及该变量的方法调用产生真正的影响。假设有另一个类 C,它有两个名称相同但签名略有不同的方法,像这样。
public class C {
public void process(A arg){
// Do some stuff
}
public void process(B arg){
// Do some other stuff
}
}
在这种特殊情况下,被调用的process 的版本取决于变量的类型,而不是对象的类。所以如果你写
C processor = new C();
A var = new B();
processor.process(var);
这将调用process 的第一个版本 - 签名中带有 A 的版本。因为变量的类型。但是如果你写
C processor = new C();
B var = new B();
processor.process(var);
这将调用process 的第二个版本 - 签名中带有 B 的那个。