ABC a1 = new XYZ();
XYZ扩展ABC的地方。
数据类型告诉我们变量将包含什么 让我感到困惑的是,如何让一个引用变量指出它不是变量?
即使我们能做到这一点,有什么好处呢?
内部如何运作。我们写的时候
ABC a1 = new XYZ();
答案 0 :(得分:2)
这种模式为您提供了灵活性。
排序算法示例:
private List<Integer> myCollectionToSort = new ArrayList<>();
ArrayList
延伸List
(从语义上讲,ArrayList
是List
,因此 IS 是List
),这一行是有效的。
对于您的算法,您可能不需要知道myCollectionToSort
是一个ArrayList。您的算法将仅使用List
接口的方法。
稍后,您会发现ArrayList
进行了大量无用的操作,而您又不想再使用它了。由于您从未使用ArrayList
的特定方法,而只使用List
接口中的方法,因此您唯一需要更改的是List
实现:
//LinkedList is more adapted for "writing" operations.
private List<Integer> myCollectionToSort = new LinkedList<>();
答案 1 :(得分:0)
想想这样:
鉴于这两个类:
class ABC {
int a;
public void getA() {return a;}
}
class XYZ extends ABC {
int x;
public void getX() {return x;}
}
编译器将这两个类加在一起:
class XYZ {
int a;
int x;
public void getA() {return a;}
public void getX() {return x;}
}
如果有任何其他可见性参数而不是公共,并且如果函数名或变量名之间存在重叠,那么它会比那更复杂,但基本上就是这样。在内存中,首先是基类的内容,然后是派生类的内容。
在内存中,你现在有类似这样的类(每个字母代表一个字节):
Class ABC: aaaa
Class XYZ: aaaaxxxx
所以当你访问这样的东西时:
ABC a1 = new XYZ();
a1.a = 5;
然后编译器将这个a1看作是一个ABC,它起作用,因为它们在对象的前四个字节中都有成员变量a。
但它不会让你做那样的事情:
ABC a1 = new XYZ();
a1.x = 5;
这是因为ABC的所有对象或其任何派生类型在前四个字节中都有成员变量a,但并非所有对象在后四个字节中都有x。只有XYZ的对象在后四个字节中具有x。因此编译器在此处抛出错误。
所以如果你写:
ABC a1 = new XYZ();
在内部看起来像这样:
a1 -> aaaaxxxx (reference a1 points to a structure containing 4 bytes a and 4 bytes x)
由于a1属于声明类型ABC(和动态类型XYZ),因此只能访问ABC中出现的成员变量(以及相应的字节)。因此,虽然有两个成员变量包含8个字节,但编译器只允许访问第一个成员变量(a)而不允许访问第二个成员变量。