Java继承 学习笔记
Java继承 学习笔记1.1类的继承1.1.1 继承格式1.1.2 extends关键字1.2继承类型1.3继承的特性1.4子类访问父类1.4.1 子类访问父类成员变量1.4.2 子类访问父类的成员方法1.5 super 与 this 关键字1.5.1 super this1.5.2 final 关键字1.6 子类构造方法1.7 再谈初始化1.7.1 代码块的执行顺序1.7.1 构造方法的执行顺序顺序一顺序二顺序三1.8protected关键字1.9 继承与组合1.1类的继承1.1.1 继承格式Java 中通过extends关键字可以声明一个类是从另外一个类继承而来的形式如下class父类{}class子类extends父类{}继承的目的是为了降低代码的重复避免代码量大且臃肿。通过提取出代码的共性实现代码的复用。要注意1.子类会将父类中的成员变量或者成员方法继承到子类中2.子类继承父类后要添加自己特有成员体现出与父类不同否则没必要经行继承。1.1.2 extends关键字在 Java 中类的继承是单一继承的也就是说一个子类只能拥有一个父类所以 extends 只能继承一个类。1.2继承类型注继承但支持多重继承。要知道事实上我们并不需要过多的继承关系这会导致向上追踪过于复杂。如果需要继承层次太多就需要考虑对代码进行重构了。一般我们不希望超过三层的继承关系。如果想从语法上进行限制继承就可以使用**final 关键字**了1.3继承的特性子类拥有父类非private 的属性、方法子类可以拥有自己的属性和方法即子类可以对父类进行扩展。子类可以用自己的方式实现父类的方法Java 的继承是单继承但是可以多重继承单继承就是一个子类只能继承一个父类多重继承就是例如 B 类继承 A 类C 类继承 B 类所以按照关系就是 B 类是 C 类的父类A 类是 B 类的父类这是 Java 继承区别于 C 继承的一个特性。提高了类之间的耦合性继承的缺点耦合度高就会造成代码之间的联系越紧密代码独立性越差。1.4子类访问父类1.4.1 子类访问父类成员变量通常子类在继承父类之后父类的成员变量就会依附在子类中。但是如果子类重新定义了与父类同名的成员变量时那么访问该变量时会优先访问子类的变量。eg:classTestA{inta1;intb2;}classTestBextendsTestA{inta1111;}//实例化 TestB b//此时System.out.println(b.a);得到的结果会是 1111总结成员变量访问遵循就近原则自己有优先自己的如果没有则向父类中找。1.4.2 子类访问父类的成员方法与访问成员变量如果名字相同以及参数相同那么会优先访问子类的。通过派生类对象访问父类与子类同名方法时如果父类和子类同名方法的参数列表不同(重载)根据调用方法适传递的参数选择合适的方法访问如果没有则报错因此引出了一个问题如果我偏偏想要访问父类的方法呢 那么就需要我们学习下面这个关键字了(super)1.5 super 与 this 关键字1.5.1 super this该关键字主要作用在子类方法中访问父类的成员。super 关键字我们可以通过 super 关键字来实现对父类成员的访问用来引用当前对象的父类。this关键字指向自己的引用引用当前对象即它所在的方法或构造函数所属的对象实例。classAnimal{voideat(){System.out.println(animal : eat);}}classDogextendsAnimal{voideat(){System.out.println(dog : eat);}voideatTest(){this.eat();// this 调用自己的方法super.eat();// super 调用父类方法}}publicclassTest{publicstaticvoidmain(String[]args){AnimalanewAnimal();a.eat();DogdnewDog();d.eatTest();}}输出结果为animal:eat dog:eat animal:eat​类以及变量都存放如图位置jdk8之后注意1.只能在非静态方法中使用2.在子类方法中访问父类的成员变量和方法。1.5.2 final 关键字final 可以用来修饰变量 包括类属性、对象属性、局部变量和形参、方法包括类方法和对象方法和类。使用final 关键字声明类就是把类定义为最终类不能被继承或者用于修饰方法该方法不能被子类重写密封类声明类finalclass类名{}声明方法修饰符(public/private/default/protected)final返回值类型 方法名(){//方法体}注意1.final 定义的类其中的属性、方法不是final 的。1.6 子类构造方法父子父子先有父再有子即子类对象构造时需要先调用基类构造方法然后执行子类的构造方法。注意是在父类显示构造方法时。子类需要去调用。父子父子肯定是先有父再有子所以在构造子类对象时候 先要调用基类的构造方法将从基类继承下来的成员构造完整然后再调用子类自己的构造方法将子类自己新增加的成员初始化完整。classBase{intage;Stringname;doublelength;publicBase(intage,Stringname){this.ageage;this.namename;System.out.println(Base constructor called);}}publicclassDerivedextendsBase{publicDerived(intage,Stringname){super(1,1);}}publicclassMain{publicstaticvoidmain(String[]args){DeriveddnewDerived(1,1);}}//输出结果为Base constructor called注意1.若父类显示定义无参或者默认的构造方法在子类构造方法第一行默认由隐含的super()调用即调用基类构造方法2.如果父类构造方法是带有参数的此时需要用户为子类显式定义构造方法并在子类构造方法中选择合适的父类构造方法调用否则编译失败。3.在子类构造方法中super(…)只能在子类构造方法中出现一次并且不能和this同时出现1.7 再谈初始化1.7.1 代码块的执行顺序classBase{publicStringname;publicintage;publicBase(Stringname,intage){this.namename;this.ageage;System.out.println(Base构造方法);}{System.out.println(Base实例代码块);}static{System.out.println(Base静态代码块);}}classDerivedextendsBase{publicDerived(){super(Derived,20);System.out.println(Derived构造方法);}{System.out.println(Derived实例代码块);}static{System.out.println(Derived静态代码块);}}publicclassMain{publicstaticvoidmain(String[]args){DeriveddnewDerived();System.out.println();DerivedenewDerived();}}//输出结果Base静态代码块Derived静态代码块Base实例代码块Base构造方法Derived实例代码块Derived构造方法Base实例代码块Base构造方法Derived实例代码块Derived构造方法我们可以得到该结论1、父类静态代码块优先于子类静态代码块执行且是最早执行的2、父类实例代码块和父类构造方法紧接着执行3、子类的实例代码块和子类构造方法紧接着在执行4、第二次实例化子对象时父类和子类的静态代码块都将不会再执行1.7.1 构造方法的执行顺序顺序一classY{publicY(){System.out.print(Y);}}classX{YynewY();// 成员变量的初始化publicX(){System.out.print(X);}}publicclassMain{publicstaticvoidmain(String[]args){XxnewX();}}//执行结果YXJava 对象的初始化顺序(记住先成员后构造在 Java 中当你new X()时发生的步骤是分配内存JVM 为X对象分配空间。初始化成员变量包括显式赋值在执行构造方法体之前先对所有 实例成员变量包括new Y()进行初始化。所以会先执行Y的构造方法打印Y。执行构造方法体然后才会进入X的构造方法打印X。顺序二classY{publicY(){System.out.print(Y);}}classXextendsY{YynewY();publicX(){System.out.print(X);}}publicclassTest{publicstaticvoidmain(String[]args){XxnewX();}}//执行结果YYX执行顺序是因为是继承父类所以先调用父类构造其次才是子类字段Y y new Y();可看作是实例代码块执行顺序最后才是子类自己的构造方法顺序三classX{YynewY();// (1)publicX(){// (2)System.out.print(X);}}classY{publicY(){// (3)System.out.print(Y);}}publicclassZextendsX{YynewY();// (4)publicZ(){// (5)System.out.print(Z);}publicstaticvoidmain(String[]args){newZ();}}//执行结果YXYZ执行new Z();顺序说明执行X里的Y y new Y(); // (1) 调用Y()构造器 进入X()构造器执行Z里的Y y new Y(); // (4) 调用Y()构造器 进入Z()构造器调用说明JVM 给Z对象分配内存成员变量先设为默认值此时X.y null,Z.y null。ZextendsX所以先去构造X。 但在调用X()构造方法体前必须先初始化X的成员变量。总结 “父变量 → 父构造 → 子变量 → 子构造”1.8protected关键字主要限制类或类中成员能否在类外或者其他包中被访问。注意父类中private成员变量虽然在子类中不能直接访问但是也继承到子类中了1.9 继承与组合组合组合并没有涉及到特殊的语法仅仅是将一个类的实例作为另一个类的字段。继承表示对象间is-a的关系狗是动物猫是动物组合表示对象间has-a的关系汽车包含轮子车座…classTire{...}classEngine{..}classVehicleSystem{...}classCar{privateTiretire;privateEngineengine;privateVehicleSystemvs;...}classBenzextendsCar{...}一般建议能用组合尽量用组合。以上是我关于继承的分享感谢你读到这里这也是我学习路上的一个小小记录。希望以后回头看时能看到自己的成长~