假设SList
是super class
的{{1}}。
如果我执行以下代码,
TailList
与执行SList s;
TailList t = new TailList();
s = t;
相同吗?
现在,静态类型仍然是SList s = new TailList();
?
答案 0 :(得分:1)
该对象将被实例化为TailList
,并且赋值不会改变它。 (如果语言可以在赋值时更改实现类,那将是一个巧妙的技巧;))
例如,你总是可以去
TailList t = new TailList();
Object o = t;
这会让它更清楚吗?该对象仍然是相同的实现类。它不会改变为Object,即使我们以这种方式引用它。
你总是可以做一个System.err.println(s.getClass()。getName())并看看。
实际上,这实际上是多态而不是继承,因为您将对象引用为层次结构中较高的类。如果您在不覆盖它的情况下调用t.slistMethod()
,则继承。
答案 1 :(得分:1)
执行SList s = new TailList();
时,会发生以下情况:
new TailList()
,创建一个运行TailList
构造函数的新对象。构造函数完成后,将返回匿名TailList
引用。TailList
引用已分配给s
。由于TailList
继承自SList
,您也可以通过它来引用它。对象的引用不会改变对象本身。
想象一下,我把垃圾桶放在某个地方,然后告诉那些不知道该物体的人是垃圾桶,我在那个位置放了一个“容器”。垃圾桶确实是一个容器,但那个人只知道它是一个容器。这并没有改变它是垃圾桶的事实,但另一个人不能安全地认为他可以把垃圾放在那里,或者计划在任何时候清空,因此他不会知道要调用这个功能在他所指的“容器”上。
例如,假设我们有以下代码:
String s = "Hello there";
Object o = s;
o
现在引用一个String对象,但是它将它视为一个“对象”,它不知道它有一个长度,或者它包含字符,即使它确实存在。
s
虽然仍在引用o
引用的同一对象,但知道此对象是String
,并且可以使用String
该对象的功能。
如果我们愿意,我们可以假设o
是一个名为“cast”的机制String
:
String s2 = (String)o;
我们现在将o
引用的对象称为String
。所有这一切都没有改变对象本身,它只是参考的一个变化。好像,对于前一个类比,被告知神秘“容器”的人会认为容器更具体地是“垃圾桶”。我们也可以做出错误的假设,即容器是一个包装容器
Integer i = (Integer)o; // throws ClassCastException
幸运的是,当我们在Java中错误地假设时,我们会得到一个ClassCastException
,与现实生活中不同的是,如果您将物品放入垃圾箱,同时将其作为包装容器引用,您的物品将被扔到垃圾箱中
new TailList()
的{{1}}部分本身是SList s = new TailList();
的构造函数的静态调用,它将始终返回TailList
引用。之后的赋值仍将引用由调用构造的TailList
对象。
TL; DR
是的,这是一回事。
答案 2 :(得分:1)
在静态类型的面向对象语言中,对象和变量都有关联的类型。
变量的类型('静态类型')由程序员在声明变量时指定。它永远不会改变。
变量引用的对象类型('运行时类型')必须是变量声明类型的相同或子类型。对象永远不会更改类型,但可以为变量分配不同类型的不同对象。
第一个代码段声明了两个变量,类型为s
的{{1}}和SList
类型的t
。它创建了一个TailList
类型的对象,并在两个变量中存储对它的引用。
第二个代码段声明了TailList
类型的变量s
,创建了SList
类型的对象,并在TailList
中存储了对它的引用。
两种情况下的最终结果是s
包含对s
类型对象的引用。不同之处在于,在第一个片段中,存在变量TailList
中存储的对象的附加引用(其仍具有静态类型t
)。
答案 3 :(得分:1)
时
TailList t = new TailList();
SList s = t;
与
相同SList s = new TailList();
是的,除了没有对新对象保持类型TailList
的单独引用,因此您只能访问SList
中的方法(除非您投射)。