继承的概念
继承是面向对象的一种概念,它允许一个类(子类)基于另一个类(父类)来构建,子类自动获取父类的属性和方法。同时可以扩展或修改这些属性和方法。 子类;继承父类的类,也成为派生类。 父类;被继承的类,也被称为基类或超类 继承主要解决的问题是:共性的抽取,实现代码复用。
继承的语法
使用extends关键字实现继承关系。子类通过extends继承父类的非私有成员(字段和方法)。
1.修饰符class子类extends父类例如;
classParentClass{// 父类的属性和方法 }classChildClassextendsParentClass{// 子类可以添加新的属性和方法// 或重写父类的方法 }注意;
1.子类可以访问父类的公共(public)和受保护(protected)成员,但私有(private)成员无法直接访问。
2.子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了
父类成员的访问
1.父类和子类成员变量不同名时直接继承即可
//父类publicclassAnimal{//成员属性publicintage;publicStringname;//成员方法publicvoideat(){System.out.println(this.name+"正在吃饭...");}}//子类继承父类publicclassDogextendsAnimal{//子类的新成员属性publicStringlive;//子类的新成员方法publicvoidbark(){System.out.println(this.name+"正在汪汪叫...");}publicstaticvoidmain(String[]args){Dogdog=newDog();//给继承父类的属性赋值dog.age=10;dog.name="大黄";dog.eat();//子类的属性赋值dog.live="中国";dog.bark();System.out.println("狗的年龄;"+dog.age+"狗的名字;"+dog.name+"狗的居住地;"+dog.live);}}2.父类和子类的成员变量同名时
publicclassAnimal{//成员属性publicintage=5;publicStringname;//成员方法publicvoideat(){System.out.println(this.name+"正在吃饭...");}}publicclassDogextendsAnimal{publicintage=10;//子类的新成员属性publicStringlive;//子类的新成员方法publicvoidbark(){System.out.println(this.name+"正在汪汪叫...");}publicstaticvoidmain(String[]args){Dogdog=newDog();System.out.println("狗的年龄;"+dog.age);注意;
在子类方法中 或者 通过子类对象访问成员时:
1.如果访问的成员变量子类中有,优先访问自己的成员变量。
2.如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
3.如果访问的成员变量与父类中成员变量同名,则优先访问自己的。
4.成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找。
子类中访问父类的成员方法
- 成员方法名字不同
publicclassAnimal{publicvoiduse2(){System.out.println("调用了Animal中的use2()...");}}publicclassCatextendsAnimal{//成员方法publicvoiduse1(){System.out.println("使用了Cat中的use1()...");}publicstaticvoidmain(String[]args){Catcat=newCat();cat.use1();cat.use2();}}总结:成员方法没有同名时,在子类方法中或者通过子类对象访问方法时,则优先访问自己的,自己没有时再到父类中找,如果父类中也没有则报错。
2. 成员方法名字相同
publicclassAnimal{publicvoiduse1(){System.out.println("调用了Animal中的use2()...");}}publicclassCatextendsAnimal{//成员方法publicvoiduse1(){System.out.println("使用了Cat中的use1()...");}publicstaticvoidmain(String[]args){Catcat=newCat();cat.use1();}}成员方法名字相同
1.当子类和父类的成员方法名字相同且参数列表也相同时,会发生方法重写(Override);如果只是名字相同但参数列表不同,则属于方法的重载(Overload),这两种情况的处理规则不同。
2.子类定义了与父类方法名、参数列表、返回值类型(或协变返回类型)完全相同的方法,称为方法重写。此时子类方法会覆盖父类方法,调用时遵循 “运行时多态” 规则。
super关键字
在子类的方法中,想要访问父类的成员时,借助super 关键字即可。
1.super可以访问⽗类的成员变量
2.super可以访问⽗类的成员⽅法
3.super还可以调⽤⽗类当中指定的构造⽅法,接下来我们看⼀下
注意:
1.只能在非静态方法中使用
2.在子类方法中,访问父类的成员变量和方法
子类的构造方法
子类构造方法在执行前,必须先调用父类的构造方法。
注意:
通过super 的形式,可以调用父类的指定的构造方法
super 的形式 只能出现在子类的构造方法中,且必须在第一行
publicclassAnimal{publicvoiduse1(){System.out.println("调用了Animal中的use2()...");}}publicclassCatextendsAnimal{publicvoiduse1(){System.out.println("使用了Cat中的use1()...");}publicvoidtest(){Catcat=newCat();cat.use1();super.use1();}publicstaticvoidmain(String[]args){Catcat=newCat();cat.test();}}总结;
初始化顺序;先父后子,本质是 “成员构成决定初始化逻辑”子类对象的成员由两部分组成:从父类继承的成员 + 子类新增的成员。
“先有父,再有子” 的逻辑决定了:构造子类对象时,必须先调用父类构造方法初始化继承的成员,再执行子类构造方法初始化新增成员。即使子类构造中未写任何父类构造相关代码,该顺序也不会改变。
2. 父类有 “无参 / 默认构造” 时:子类默认隐含super()调用若父类显式定义了无参构造(如public Parent() {}),或未定义任何构造(编译器自动生成默认无参构造),则子类构造方法的第一行会隐含super()(无需手动写),自动调用父类的无参构造。
3. 父类只有 “有参构造” 时:子类必须显式调用父类``有参构造若父类仅定义了带参数的构造(无无参构造),编译器无法自动生成super()(因找不到父类无参构造),此时必须:手动为子类定义构造方法;
在子类构造方法的第一行,通过super(参数)显式调用父类的某一个有参构造,否则编译报错。
publicclassBase{inta;intb;//给Base构造方法Base(inta,intb){this.a=a;this.b=b;}}publicclassSubextendsBase{//必须给Sub构造方法且给Base中的成员初始化Sub(){super(5,10);}}super和this
在Java中super和this都属于与关键字。
1.this指代当前的对象
其用于以下场景;
区分实例变量和局部变量,当方法参数和成员变量同名时,用this指定访问成员变量
publicclasstest{privateinta;publicvoidset(inta){this.a=a;// this.value 指实例变量,value 指方法参数}}在构造方法中调用其他构造方法
通过 this() 可以在一个构造方法中调用同一类的另一个构造方法,但必须将其放在构造方法的第一行。
publicclassExample{privateintx;privateinty;publicExample(intx,inty){this.x=x;this.y=y;}publicExample(){this(0,0);// 调用带参数的构造方法}}作为方法的返回值
this 可以作为方法的返回值,返回当前对象的引用,常用于链式调用。
classBuilder{privateStringinfo;publicBuildersetInfo(Stringinfo){this.info=info;returnthis;// 返回当前对象}}// 链式调用newBuilder().setInfo("test");2.super指代父类的对象
主要运用的场景;
访问父类成员变量
若子类与父类有同名变量,使用super.variable可明确指定访问父类变量。
classParent{Stringvalue="Parent";}classChildextendsParent{Stringvalue="Child";voidshow(){System.out.println(super.value);// 输出 ParentSystem.out.println(value);// 输出 Child}}访问父类成员方法
当子类重写父类方法时,可通过super.method()调用父类被覆盖的方法,避免递归调用。
classParent{publicvoidshow(){System.out.println("父类方法");}}classChildextendsParent{@Overridepublicvoidshow(){super.show();// 调用父类的show()System.out.println("子类方法");}}调用父类的构造方法
用super(参数)在子类构造方法中调用父类的构造方法,必须放在子类构造方法的第一行。
classParent{Parent(Stringname){System.out.println("Parent: "+name);}}classChildextendsParent{Child(){super("Alice");// 必须显式调用父类有参构造器}}相同点:
1.都是Java的关键字
2.只能在类的非静态方法中使用,用来访问非静态成员方法和字段
3.在构造方法中调用时,必须是构造的第一条语句,并且不能同时存在
不同点:
1.this 是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成员的引用。
2.在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性
3.在构造方法中,this(…)用于调用本类的构造方法,super(…)用于调用父类的构造方法,两种调用不能同时在构造方法中出现
4.构造方法中一定会存在super(…)的调用,用户没有写编译器也会增加,但是this(…)用户不写则没有
publicclassAnimal{Animal(){System.out.println("Animal()...");}static{System.out.println("调用了Animal静态方法...");}{System.out.println("调用了Animal实例方法...");}}publicclassCatextendsAnimal{static{System.out.println("调用了Cat的静态方法...");}{System.out.println("调用了Cat的实例方法");}Cat(){System.out.println("调用了Cat()构造方法");}publicstaticvoidmain(String[]args){Catcat1=newCat();System.out.println(" 1===========1");Catcat2=newCat();}}执行结果;
调用了Animal静态方法…
调用了Cat的静态方法…
调用了Animal实例方法…
Animal()…
调用了Cat的实例方法
调用了Cat()构造方法
1===========1
调用了Animal实例方法…
Animal()…
调用了Cat的实例方法
调用了Cat()构造方法
注意;
- 静态代码块先执行,并且只执行一次,在类加载阶段执行
- 当有对象创建时,才会执行实例代码块,实例代码块执行完成后,最后构造方法执行