💕"越是不思考的人,越不愿倾听别人说话。"💕
作者:Mylvzi
文章主要内容:JavaSE学习之--继承和多态
一.继承(inheritance)
1.为什么要有继承
我们前面学过类,类是对现实事物的抽象化处理,而通过类实例化的对象则可以用来表示事物。在现实生活中,事物与事物之间有着千丝万缕的联系,最常见的一种就是“父子关系”,儿子会继承父亲的很多特征,而自己又有自己独特的特征;再比如狗和猫都是动物,都具有动物的一些属性,如年龄,性别,毛发颜色等等等等;为了在计算机中表示这种关系,创建了“继承”!
2.继承的概念
继承(inheritance):就是对事物共性的抽取,从而实现代码复用;
从和实际生活的联系来讲,继承就是将事物的共同属性抽取出来,用一个大类来表示,比如一个父亲有多个孩子,这些孩子都具有某些共性,如年龄,性别,将这些共同属性抽取出来,创建一个新类“Child”;
从代码实现来讲,继承关系的存在实现了代码的复用,子类继承了父类的属性和方法,大大提高效率;
补充:
其实Java中有很多这种“对共性进行抽取从而达到代码复用”的思路,比如前面学过的类变量,就是所有对象的共同属性的抽取
对象的共性-->静态成员变量
类的共性-->继承extends
3.继承的语法及代码实现
// 父类 class Animal { String name; int age; public void eat() { System.out.println(name+"i am eating!!!"); } public void sleep() { System.out.println(name+"i am sleeping!!!"); } } // 子类 // 通过关键字extends表示此类继承于父类 class Dog extends Animal { public void bark() { System.out.println(name+"汪汪叫!!!"); } } class Cat extends Animal { public void mew() { System.out.println(name+"喵喵叫!!!"); } } public class Test { public static void main(String[] args) { Dog dog1 = new Dog(); dog1.name = "初一"; dog1.age = 3; // dog1的成员变量中并没有name和age,但却能引用,则一定继承于父类 System.out.println(dog1.name); System.out.println(dog1.age); dog1.eat(); dog1.sleep(); dog1.bark(); } }
总结:
1. 继承关键字-->extends,格式为:class 子类 extends 父类
2.子类会继承父类的成员和方法,实例化对象之后直接通过对象就能访问
3.子类继承父类的成员和方法之后,还需要有不同于父类的成员或方法(比如Dog类中的bark)
4.在子类中访问父类成员-->super关键字
1.子类中访问父类成员
11.不存在同名成员变量
class Base { int a; int b; public void method1() { System.out.println("hello1"); } } class Derived extends Base { int c;// 类特有的 public void method2() { a = 30;// 访问父类继承下来的变量 b = 20;// 访问父类继承下来的变量 c = 10;// 访问子类自己的变量 }
1.2存在同名成员变量
class Base { int a; int b; public void method1() { System.out.println("hello1"); } } class Derived extends Base { int a;// 和父类同名 int c;// 子类特有的 public void method2() { a = 30;// 究竟是给父类赋值,还是给子类赋值? b = 20; c = 10; }
1.3在子类中访问成员方法
class Base { int a; int b; public void method1() { System.out.println("hello1"); } } class Derived extends Base { int c; // 和父类的方法构成了重载 public void method1() { System.out.println("hello2"); } // 子类特有的方法 public void method2() { System.out.println("hello2"); } } public class TestDemo1 { public static void main(String[] args) { Derived p1 = new Derived(); p1.method1(); p1.method2(); // 输出hello1 hello2 // 证明先执行子类的方法 // 既不属于子类,又不属于父类,编译失败 // p1.method3(); } }
总结:
1.父类,子类存在同名的成员变量,成员方法,优先访问子类的,子类中没有再去父类中寻找,寻找不到就编译报错
2.子类和父类可构成方法的重载,将参数列表设置为不同,在调用时通过传参调用不同的方法!
1.3 那如何在子类中访问父类的成员呢?通过super关键字!
由于设计不好或者特殊场景需要,需要在子类中访问父类成员,但如果出现重名编译器会优先访问子类中的,并不会访问父类中的成员变量,那该怎么解决呢?Java中提供了关键字super,该关键字的作用是-->在子类方法中访问父类成员变量
class Base { int a; int b; public void method1() { System.out.println("hello1"); } } class Derived extends Base { int a; int b; int c; public void method1() { a = 10;// 等价于this.a b = 20;// 等价于this.b // 通过super关键字来访问父类成员 super.a = 30; super.b = 40; }
super访问方法:
class Derived extends Base { int a; int b; int c; public void method1() { System.out.println("hello2 这是子类方法"); } public void method2() { a = 10;// 等价于this.a b = 20;// 等价于this.b // 通过super关键字来访问父类成员 super.a = 30; super.b = 40; method1();// 输出hello2 super.method1();// 输出hello1
总结:
1.super关键字的作用就是在子类方法中访问父类成员变量和方法!
2.super只能在子类的非静态方法中使用,因为super主要用来访问并实例化父类中的实例变量,而实例变量必须依赖于对象,静态方法不依赖于对象,所以super不能在子类的静态方法中使用! (super可以访问父类的类变量,但是不建议,更建议通过类名)
3.super只是关键字,提升了代码的可读性,并不代表对父类成员的引用!
1,4子类的构造方法
构造方法是用来初始化成员变量的一种特殊方法,其在对象的创建过程中就会被调用,而且即使你不写构造方法,编译器会默认添加一个不带参数的构造方法,给你的成员变量赋初始值;在子类中,既有从父类继承过来的成员变量,又有自己独有的成员变量,那在构造方法中赋值的顺序有没有要求呢?答案是有的,先上结论:
必须先对父类成员变量进行初始化才能对子类成员变量进行初始化!
也就是说在子类的构造方法中会先调用对父类的构造方法,再对子类的成员变量进行初始化。
class Base { int a; int b; // 父类的构造方法 public Base() { System.out.println("父类的构造方法!!!"); } } class Derived extends Base { int a; int b; int c; public Derived() { // 会默认有一个不带参数的super() // 代表父类的初始化 System.out.println("子类的构造方法!!!"); } }
注意事项:
super()就代表调用父类的构造方法!!!
和this();的含义一样!!!
1.super只能放在第一行,放在其他行就报错
2.如果父类的构造方法带参数,则在子类中调用父类的构造方法时也要带参数!(可以快速创建)
// 带参数的父类的构造方法 public Base(int a, int b) { this.a = a; this.b = b; System.out.println("这是父类构造方法"); } // 子类中的构造方法 // 必须先对父类成员变量进行初始化 public Derived(int a, int b, int a1, int b1, int c) { super(a, b);// 必须放在第一行 // 且必须要传参数 this.a = a1; this.b = b1; this.c = c; System.out.println("这是子类构造方法"); }
注意:如果父类提供的是一个显式的构造方法,则在子类中必须利用super进行传参!!!
如果父类的构造方法不带参数,在子类的构造方法中可以不写,因为系统会自动提供一个不带参数的super();
3.在子类的构造方法中super和this不能同时出现,且super只能出现一次
在构造方法那一节我们学过,对于一个类的构造方法,如果要使用this来调用当前类的其他构造方法,则this只能放在第一行,那如果我既想通过super来初始化父类的成员变量,又想通过this调用当前类的其他构造方法该怎么办?答案是没有办法,如果同时拥有会冲突,只能保证他们不能同时存在!
为什么只能出现一次呢?原因在于继承结构的逻辑链!在继承结构中,子类会先调用父类的构造方法,再执行自身的初始化逻辑,这种执行顺序是线性的,不需要多次进行父类的初始化!
1.5super和this的比较
我们学过super和this,发现他们有很多相同点,比如都是通过.操作符来访问变量或方法,那他们有哪些异同点呢?下面来总结一下:
相同点:
1.都是Java中的关键字。
2.都只能在非静态方法中访问非静态成员变量或非静态方法
3.在构造方法中调用时,都必须写在第一行,所以super和this不能同时使用;
不同点:
1.this代表当前对象的引用,用于访问当前对象的成员变量及方法;super是用来访问从父类继承的成员或方法。或者说super是引用对象从父类继承部分的引用
2.在构造方法中,super会有默认的对父类的构造方法(先有父后有子),而this并没有默认的构造方法。
3.this(......) 代表当前对象的构造方法,super(.......)代表父类的构造方法,两者不能同时出现
JavaSE学习之--继承和多态(二)+https://developer.aliyun.com/article/1413490