继承
引出继承
发现Teacher Student Employee 中存在着共同的代码:
继承思想
继承关系:
基于某个父类对对象的定义加以拓展,二产生新的子类定义,子类可以继承父类的某些定义,也可以增加原来父类没有的定义,或者覆盖父类的某些特性.
从面向对象的角度来说:继承是一种从一般到特殊的关系,是一种 ”is a” 的关系,即子类是对父类的拓展,是一种特殊的父类,是一种特殊的父类.比如:狗属于动物,但狗是动物的一种特殊情况.
在Java语言中,存在多个类的时候,我们使用--extends--关键字来表示子类和父类之间的关系.
语法格式:在定义子类的时候来表明自己需要拓展于哪一个父类
Public class 子类类名 extends 父类类名
{
编写自己特有的状态和行为
}
在Java中,类和类之间的继承关系,只允许单继承,不允许多继承.
也就是说一个类A,只能有一个直接的父类,不能出现类A同时出现继承与类B和类C.
但是Java中允许多重继承.
在Java中,除了Object类之外,每一个类都有一个直接的父类
比如:class Student extends Person{}
我们就说此时Student的直接父类是Person
问题: class Person{},此时Person的父类又是谁呢?
Object类是Java语言的根类(老祖宗,任何类都是Object的子类)
Class Person{} 等价于 class Person extends Object{};
Object类要么是一个类直接父类,要么是一个类间接父类.
继承关系的作用:
1):解决代码的重复问题
2):真正的作用是表达一个体系.
先写父类还是先写子类:
一般在开发过程中,先编写多个自定义的类,写完之后发现多个类之间存在共同的代码,此时可以抽出去一个父类.
以后做开发都是基于框架/组件来做的,我们 是在别人的基础上做的,继续做开发.
以后我们定义新的类去继承与框架中/组件中提供的父类
子类继承父类之后,可以拥有父类的某一些状态和行为(子类复用了父类的功能和状态).
子类到底继承了父类的哪些成员(根据访问修饰符来判断):
1):如果父类中的成员使用了public修饰,子类继承
2):如果父类中的成员使用了protected修饰,子类也继承,即使父类和子类不再同一个包中.
3):如果父类和子类在同一个包中,此时子类可以继承父类中缺省修饰符的成员.
4):如果父类中的成员使用private修饰的,子类打死都继承不到,因为private只能在本类中访问.(跟static没有任何关系)
5):父类的构造器,子类也不能继承,因为构造器必须和当前的类名相同.
方法覆盖
子类拓展了父类,可以获得父类的部分方法和成员变量.可是当父类的某个方法不适合于子类本身的特征时,此时怎么办?
方法覆盖的原则(一同两小一大):
一同:
① 实例方法签名必须相同.(方法签名 = 方法名 + 方法的参数列表);
两小:
② 子类方法的返回类型是和父类方法的返回值相同或者是其子类(Runtime Exception类型除外);
③ 子类方法抛出的异常类型和父类方法的声明抛出的异常类型相同或者是其子类.(Runtime Exception类型除外);
一大:
④ 子类方法的访问权限比父类方法访问权限更大或者相等.(public > protected > 无修饰)
Private修饰的方法不能被子类多继承,也就不存在覆盖的概念
判断是否是覆写方法的必杀技:@Override标签:若方法是覆写方法,在方法前或上贴上该标签,编译通过. 否则, 编译出错.
只有方法有覆盖的概念,字段没有覆盖.
方法覆盖解决的问题:当父类的某一个行为不符合子类具体的特征的时候,此时子类需要重新定义
Super关键字
需求:在子类的某一个方法中,去调用父类被覆盖的方法
此时的解决方案:使用super关键字
什么是super:
This:当前对象,谁调用this所在的方法,this就是哪一个对象.
Supper: 当前对象的父类对象.
子类初始化的过程:创建子类对象的过程,
在创建子类对象之前,会先创建父类对象.
调用子类构造器之前,在子类构造器中会先调用父类的构造器
默认调用的是无参数构造器..
1):如果父类不存在无参数的构造器,则不能存在子类.
2):如果父类没有提供无参数构造器,此时子类必须显示通过super语句去调用父类带参数的构造器.
Super关键字的使用场景:
1):可以使用super解决子类隐藏父类的字段的情况.该情况我们一般不讨论,因为破坏封装.
2):在子类方法中调用父类被覆盖的方法.此时必须使用super.
3):在子类构造器中,调用父类构造器,必须使用super语句:super(实参).
所谓隐藏就是”遮蔽”的意思.
① 满足继承的访问权限下,隐藏父类的静态方法:若子类定义的静态方法的签名和父类中的静态方法签名相同,那么此时就是隐藏父类方法.
注意:仅仅是静态方法.子类存在和父类一模一样的静态方法.
② 满足继承的访问权限下,隐藏父类字段:若子类中定义的字段和父类中的字段名相同(不管类型),此时是隐藏父类字段.此时只能通过super访问被隐藏的字段.
③ 隐藏本类字段: 若本来中某局部变量和字段名相同,此时就是隐藏本类字段,此时只能通过this访问被隐藏的字段.
Static不能和super以及this共存
Static属于类级别,super和this属于对象级别,所以不能共存.否则程序报错.
Java语言的根类:Object
Object类是Java语言的根类,要么是一个类的直接父类,要么是一个类的间接父类.
Class ABC{} 其实等价于 class ABC extends Object{};
为什么Object是什么类的根类?
Object本身是对象的意思,我们发现所有的对象都具有某一些相同的行为,所以我们抽象出一个类:Object,表示对象类,其他都会继承于Object类,也就是说拥有Object类中的方法.
引用数据类型:类/接口/数组,引用数据类型又称之为对象类.所谓的数组变量名称,应该指数组对象.
Object类常见方法:
1): finalize() 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。 垃圾回收期在回收某一个对象之前,会先调用该方法,该方法我们不要去调用.
2):getClass()
返回此 Object
的运行时类.
3):hashCode()
返回该对象的哈希码值。hasCode决定了对象再哈希表中的储存位置,不同对象的hadcode是不一样的.
4):boolean equals(
Object obj)
拿当前对象this与参数obj作比较。
在Object类中的equals方法本身和”==”符号相同,都是比较对象的内存地址
官方建议:每一个都应该覆盖equals方法,必要比较内存地址,而去比较我们关心的数据.
5):toString()
表示把一个对象转换成字符串.
打印对象时,其实打印的就是对象的toString方法.
System.out.println(obj对象) 等价于 System.out.println(obj对象 . toString);
默认轻快下打 印对象的是对象的十六进制的hascode值,但是我们更关心对象中储存的数据.
官方建议我们:应该每个类都应该覆盖toString,返回我们关心的数据