面向对象三大特性之继承
继承的概念
生活中的继承:父辈对子女的进行财产的赠与,父辈的赠与 子女的获得
程序中的继承:类与类之间满足is a关系 才能定义继承关系 是指 子类可以去获得父类中非私有的属性和方法
is a关系理解
保温杯 is a 杯子
桑豪 is a 人
电脑 is a 电器
里氏代换原则 要求必须满足 is a 关系才可以定义两个类的继承关系
继承语法
关键词:extends 继承
语法: 子类extends 父类
代码:publicclassDemo{}//狗 动物classDogextendsAnimal{}classAnimal{}
案例:publicclassDemo{publicstaticvoidmain(String[] args){//创建狗类对象Dog d=newDog();
d.name="哈士奇";
d.age=15;
d.eat();}}//狗 动物classDogextendsAnimal{}classAnimal{//属性String name;int age;//吃publicvoideat(){System.out.println("动物吃");}}
注意事项
1.构造方法不可以继承2.不能为了代码的复用去定义不符合里氏代换原则的继承关系
案例:
桑邦豪
刘洋 教java 没头发
桑邦豪extends 刘洋{
}
java继承的特点
特点:、1.java是单继承 一个类只能有一个父类2.java可以多层继承 子类中的属性和方法是其所有父类的属性和方法的叠加
单继承的必要性:单继承可以让类和类之间的关系变得简单 让类和类之间形成一个树状结构
树状的结构
爷爷()
爸爸 叔叔 大爷
你 亲弟弟 堂弟 堂哥
```jaba
###Java的继承的好处
1.提高了代码的复用性(次要的) 不能为了代码的复用性强制定义不符合里氏代换原则原则的继承关系
2.是多态的前提
### 访问修饰符| 修饰符| 本类| 同包及同包子类| 其他包子类| 其他||-------------------|----|--------------|----------|----||private 私有的|*||||| (default)默认的|*|*||||protected 受保护的|*|*|*|||public 公开的|*|*|*|*|
```java
案例:packagecn.baizhi.day09;publicclassA{publicint a;publicvoidm1(){System.out.println(a);}}//同包classB{publicvoidm2(){A a=newA();System.out.println(a.a);}}//同包的子类classCextendsA{publicvoidm3(){System.out.println(a);}}=================================================================packagecn.baizhi.day09_1;importcn.baizhi.day09.A;//不同包子类classDextendsA{publicvoidm4(){System.out.println(a);}}//不同包 也没有继承关系classE{publicvoidm5(){A a=newA();System.out.println(a.a);}}
方法的重写(Override)
概念:当父类中的方法的实现无法满足子类的需要,那么就需要在子类中定义和父类方法名相同参数列表相同但是方法的实现不同的方法,把这种现象叫做方法的重写(覆盖)
要求:1.方法名相同2.参数列表相同3.访问权限相同或者更宽4.返回值类型相同
特点:当子类对象调用被重写后的方法时,调用的是子类中覆盖以后的方法
注意:1.方法的重写前提是存在继承关系,才会有子类重写父类的方法2.private修饰的方法不能被继承,也就谈不上覆盖
案例:publicclassDemo{publicstaticvoidmain(String[] args){Dog d=newDog();
d.eat();//狗汪汪的吃}}classAnimal{publicvoideat(){System.out.println("动物吃");}}classDogextendsAnimal{publicvoideat(){System.out.println("狗汪汪汪吃");}}
案例:关于访问权限修饰符publicclassDemo{publicstaticvoidmain(String[] args){Dog d=newDog();
d.eat();}}classAnimal{voideat(){System.out.println("动物吃");}}classDogextendsAnimal{publicvoideat(){System.out.println("狗汪汪汪吃");}}
案例:关于private修饰的方法能不能被覆盖publicclassDemo{publicstaticvoidmain(String[] args){Dog d=newDog();
d.eat();}}classAnimal{privatevoideat(){System.out.println("动物吃");}}classDogextendsAnimal{publicvoideat(){System.out.println("狗汪汪汪吃");}}
案例:关于子父类间方法的重载publicclassDemo{publicstaticvoidmain(String[] args){Dog d=newDog();
d.eat();}}classAnimal{publicvoideat(){System.out.println("动物吃");}}classDogextendsAnimal{publicvoideat(String s){System.out.println("狗汪汪汪吃"+s);}}
总结重载(overload)和重写(override)
重载1.方法名相同2.参数列表不同3.和修饰符返回值类型无关
重写1.方法名相同2.参数列表相同3.返回值类型相同4.访问修饰符权限相同或者更宽
创建对象的过程
在创建子类对象之前 会先创建父类对象 子类对象的创建是依赖于父类对象
案例:publicclassDemo{publicstaticvoidmain(String[] args){Dog d=newDog(撒谎角度来看);}}classAnimal{publicAnimal(){System.out.println("动物类构造被调用");}}classDogextendsAnimal{publicDog(){super(累计收到啦看风景);System.out.println("狗类的构造被调用");}}
总结创建对象的过程
之前:1.分配空间并赋默认值2.为属性进行初始化赋初始值3.调用构造方法并赋值创建对象
现在:
分配空间
创建父类对象
父类属性赋默认值1为父类属性进行初始化赋初始值2调用父类的构造方法并赋值创建父类对象
创建子类对象
子类属性赋默认值3为子类属性进行初始化赋初始值4调用子类的构造方法并赋值创建子类对象
注意:如果一个类是多层继承12 重复执行
案例:publicclassDemo{publicstaticvoidmain(String[] args){Dog d=newDog();}}classShengWu{publicShengWu(){System.out.println("生物类的构造被调用");}}classAnimalextendsShengWu{publicAnimal(){System.out.println("动物类构造被调用");}}classDogextendsAnimal{publicDog(){System.out.println("狗类的构造被调用");}}
super关键字
案例:publicclassDemo{publicstaticvoidmain(String[] args){Dog d=newDog();}}classAnimal{//属性String name;int age;//无参publicAnimal(){System.out.println("动物类无参构造被调用");}// 一参publicAnimal(String name){System.out.println("动物类一参构造被调用");}//两参publicAnimal(String name,int age){System.out.println("动物类两参构造被调用");}}classDogextendsAnimal{publicDog(){System.out.println("狗类的构造被调用");}}
存在问题:在创建子类对象的时候,默认调用的是父类中无参构造,无法调用父类有参的构造
super()和super(参数)
super():代表调用父类无参的构造super(参数):调用父类有参的构造
作用:在子类构造方法中调用父类的构造方法
特点:1.如果子类构造方法中的第一行没有this()或者this(参数),也不是super(参数) 默认是super(),构造方法的第一行不是this(...)就是super(...)2.super()和super(参数)只能在构造方法的第一行
注意:super()和super(参数)只能用在子类的构造方法中
案例: 关于super()使用的位置publicclassDemo{publicstaticvoidmain(String[] args){Dog d=newDog();
d.m1();}}classAnimal{//属性String name;int age;//无参publicAnimal(){System.out.println("动物类无参构造被调用");}// 一参publicAnimal(String name){System.out.println("动物类一参构造被调用");}//两参publicAnimal(String name,int age){System.out.println("动物类两参构造被调用");}}classDogextendsAnimal{publicDog(){super();System.out.println("狗类的构造被调用");}publicvoidm1(){super();}}
案例:publicclassDemo{publicstaticvoidmain(String[] args){Dog d=newDog("哈士奇");}}classAnimal{//属性String name;int age;//无参publicAnimal(){System.out.println("动物类无参构造被调用");}// 一参publicAnimal(String name){this.name= name;System.out.println("动物类一参构造被调用");}//两参publicAnimal(String name,int age){System.out.println("动物类两参构造被调用");}}classDogextendsAnimal{publicDog(){super("金毛");System.out.println("狗类的构造被调用");}publicDog(String name){super(name);System.out.println("狗类的有参被调用");}}
总结:this()和this(参数):在一个类中的构造方法中调用其他的构造方法(本类)super() 和super(参数):在子类中调用父类的构造方法
super.
this.属性名:局部变量和成员变量重名问题(本类)super.属性名:子类的成员变量和父类成员变量重名问题 访问的是子类的 直接父类 中的重名属性值super 代表当前子类对象的父类对象的引用
案例:publicclassDemo{publicstaticvoidmain(String[] args){Dog d=newDog();
d.m1();}}classAnimal{int age=10;//父类的成员变量}classDogextendsAnimal{int age=20;//子类的成员变量publicvoidm1(){int age=30;//子类的局部变量System.out.println(age);//30System.out.println(this.age);//20System.out.println(super.age);//10}}
案例:publicclassDemo{publicstaticvoidmain(String[] args){Dog d=newDog();
d.m1();}}classAnimal{int age=10;//父类的成员变量}classDogextendsAnimal{publicvoidm1(){int age=30;//子类的局部变量System.out.println(age);//30System.out.println(this.age);//10System.out.println(super.age);//10}}
案例:关于直接父类和间接父类的属性名重名问题publicclassDemo{publicstaticvoidmain(String[] args){Dog d=newDog();
d.m1();}}classShengWu{//间接父类int age