* 对于每一个初学者来说,Java继承(或者说任何语言的继承)都是一个难点,继承的机制让我们有点摸不着头脑,我们使用继承之后还需要看两个类之间 权限,属性和方法各自的区别,还有访问属性和方法函数的方式等等,经过学习之后对于继承有了一点自己的理解,那么我就来记录一下我学习过程中的发现和感悟,希望能对与正在看这篇文章的你有所帮助,同时,我也欢迎大家帮忙指正不对的地方,相互提高:
复习一下Java继承机制:
- Java的继承是通过extends关键字来实现的
- 子类通过继承拥有父类的属性和非private方法
- 子类可以不通过super访问父类的非private属性和方法
- 子类可以通过super关键字来直接访问父类中(被覆写)的方法
Java继承发生之后,如果用new关键字来产生子类的实例化对象,子类对象会先调用父类的默认构造方法(一般都是无参构造方法)super(),先产生一个父类的实例化空间,再在其基础上调用子类自身的构造方法创造实例化空间。
1.为什么要向上转型?
1.1为什么要指明具体类型?
我们使用的方法都需要指明具体的参数类型,如 :
public static int add(int x, int y){ //参数都指明为int类型
return x+y;
}
不指定具体类型的泛型工具类其实在声明的时候也会确定具体类型:
List<Integer> list = new ArrayList<Integer>(); //指明类型为Integer类型
为什么需要指定类型呢?因为我们的数据在计算机中都是由 0 和 1 (高低电位)来存储的,我们程序读取数据的时候是通过数据的类型来读取的,比如:
class Test{
public static void main(String[] args){
char c = 'A';
int a = c;
System.out.println("char c =" + c); //char c =A
System.out.println("int a = " + a); //int a = 65
}
}
这个程序声明了一个字符变量c,赋值为:'A' ,但是用一个 int 类型的变量来接收 c 的值,结果输出 a 的值为65,这是因为字符变量是用ASCALL码表示的。这代表着,如果我们向计算机中存放了一个字符 'A' 数据,而计算机是以 int 类型的方式来读取数据的,这就导致了读数据错误。
试想如果我们没有指定数据类型,那么计算机怎么知道该以何种方式读取数据呢?又该怎么保证读取数据的正确性?所以我们必须要指定好数据类型,为计算机的正确执行提供保障。
1.2 向上转型的"原理"(注:概念模型仅供参考)
注:我个人比较倾向把“声明变量”换成“类型引用”,如:
int a = 0; 我把 int a 称为“声明一个int类型的引用,引用名为 a ,给这个引用 a 赋值为 0”; Person p = new Person(); "声明一个Person类型的引用,引用名为 p,给这个引用赋值为一个实例化的Person对象"
这对于理解Java继承、向上转型有很大帮助
因为Java继承发生之后,子类实例化对象的时候实际上调用了多次构造方法,可以理解为产生了一个**“有层次”的实例化对象空间(假设有三层),第一层是Object的实例化空间(Object是所有类的父类),第二层是父类对象的实例化空间,第三层是子类对象的实例化空间,那么我们用 Father f = new Child();来声明引用和实例化的时候,实际上是 f 指向了(其实是引用了)第二层也就是Father的实例化空间,同样的道理,用 Object o = new Child();的时候,实际上是 o 引用了第一层实例化空间,并不是Father或者Object对象兼容了它们的子类对象,这个解释方法**比较好的说明了为什么使用了向父类转型后,只能使用父类的属性和方法(被覆写的方法后面解释),要用到子类本身的属性和方法的话必须转型回来。
我们从这里可以看出计算机编译器对于数据的类型还是很严格的,只有类型相同才能引用,不过技术的缔造者们用他们惊人的想象力和创造力突破了这个限制,让技术得以继续向更高处发展,真的十分佩服他们的智慧。
1.3 向上转型的优点
Java继承机制解决了一部分代码复用的问题,是面向对象中的一个重要的概念,同时,它又促使了转型机制的出现:具有继承关系的两个类能实现父对子引用,和类型相互转换。
我们所说的向上转型其实都是子类的实例化对象为父类引用赋值:
Father f = new Child(); //父类类型Father的引用,引用名为f,赋值为一个实例化的子类Child对象
这就是父类引用子类,父类引用的其实是子类的实例化对象,在引用的时候其实也做了转型处理,
向上转型实现了父类可以引用子类,那么现在如果一个类 Person 有很多子类,如果一个方法public static Method()可能会需要用到它的大部分子类,这个时候我们写代码的时候直接把参数类型声明为Person:public static Method(Person p),这样无论我们传入的是Person的哪一个子类,方法都可以接收并引用它,我们避免了为每个Person子类都写一个方法,这又大大减小了代码复杂度、提高了代码的复用性。
总结一下:向上转型解决了对象引用和传递的问题,同时也在一定程度上提高了代码的复用性
CopyRight @Kirito ——转载请注明出处