java继承
系列文章目录
第一章 万事万物皆对象
第二章 java构造器
第三章 java访问权限
第四章 java初始化
第五章 java继承
第六章 java重载与重写
第七章 java接口和抽象类
第八章 java数组
第九章 java内部类
第十章 java时间操作
第十一章 final关键字
第十二章 java字符串
第十三章 java异常
第十四章 java泛型
第十五章 java IO操作
第十六章 java NIO操作
第十七章 java zip压缩
第十八章 java反射
第十九章 java反射之Type接口
第二十章 java8流式操作
第二十一章 java8函数式编程
原文链接 https://zhhll.icu/2020/java基础/面向对象/5.java基础之继承/
为了避免重复代码太多,导致代码不好维护,大家需要学会如何复用代码,代码复用的两种方式,组合和继承
组合:在新类中创建现有类的对象 has-a
继承:创建现有类的新类 is-a
依赖:uses-a
继承
继承使用的关键字是extends,Object是所有类的父类,在Java中每个类都是由Object扩展来的,如果没有明确地指出父类,Object就被认为是这个类的父类
继承中的构造方法调用
子类在自己的构造方法调用父类构造方法时可以使用super(参数列表)来调用,注意在调用时要写在构造方法的第一行
super的作用
- 调用父类的方法
- 调用父类的构造器
多态
存在多态的必要条件
- 继承
- 方法重写
- 父类引用指向子类对象
向上转型
class Instrument {
public void play() {
System.out.println("Instrument.play()");
}
}
public class Wind extends Instrument {
public void play() {
System.out.println("Wind.play()");
}
}
public class Music {
public static void tune(Instrument i){
i.play();
}
public static void main(String[] args) {
Wind flute = new Wind();
Music.tune(flute); // 向上转型
}
}
从一个更具体的类型转化为更一般的类型,所以向上转型用法是安全的。子类可能会比父类包含更多的方法,必须至少具有和父类一样的方法。
instanceof
可以在进行类型转换时使用instanceof来判断该对象是否属于该类或者该类的子类,以此来进行强转,调用该类所特有的方法
// 获取父类的泛型
if(superType instanceof ParameterizedType){ // 如果存在泛型
Type[] actualTypeArguments = ((ParameterizedType) superType).getActualTypeArguments();
}
方法绑定
对于上述向上转型的例子,编译器如何知道该调用哪个方法,方法的入参只是一个Instrument引用?
java采用后期绑定,在运行时根据对象的类型进行绑定,在运行时判断对象的类型,从而调用方法,在编译时编译器不知道对象的类型,java对于static和final方法无法采用后期绑定(private方法也是隐式的final)
调用的过程
- 编译器查看对象的声明类型和方法,此时会一一列举出该类以及父类中名称为方法名的方法(父类的私有方法不可访问)
- 编译器查看调用方法时提供的参数类型
- 如果是private方法、static方法、final方法或者构造器,那么编译器可以准确地知道应该调用哪个方法,这种调用方式称为静态绑定;如果调用的方法依赖于隐式参数的实际类型,并且在运行时实现动态绑定
- 当程序运行,并且采用动态绑定调用方法时,虚拟机一定调用所引用对象的实际类型最适合的那个类的方法
由于每次调用方法都要进行搜索,时间开销较大,所以虚拟机预先为每个类创建了一个方法表,其中列出了所有方法的签名和实际调用的方法
多态的陷阱
注:多态只是针对于普通方法,对于属性和静态方法不会存在多态
属性在编译时就会被解析
public class Parent {
public int field = 0;
public int getField(){
return field;
}
}
public class Child extends Parent {
public int field = 1;
@Override
public int getField(){
return field;
}
}
public class TestField {
public static void main(String[] args) {
Parent parent = new Child();
System.out.println("parent.field= "+parent.field);
System.out.println("parent.getField= "+parent.getField());
Child child = new Child();
System.out.println("child.field= "+child.field);
System.out.println("child.getField= "+child.getField());
}
}
执行结果
parent.field= 0
parent.getField= 1
child.field= 1
child.getField= 1
Parent.field和Child。field被分配了不同的存储空间,Child其实是存在两个filed属性的:本身的以及父类的,但是在引用Child的field的时候,默认的field属性是来自于本身的,如果要获取父类的该属性,需要使用super.field来显示地指定获取父类属性
但是这种情况一般不会发生,首先属性一般来说都是私有private的,其次子类和父类一般也不会起相同的属性名字
对于静态方法的话,静态方法只与类关联,与对象无关
本文来自博客园,作者:拾光师,转载请注明原文链接:https://www.cnblogs.com/life-time/p/17864414.html 个人博客-> https://zhhll.icu