java--继承篇!!

目录

1.继承

2.子类访问父类的成员变量

3.子类访问父类的成员方法

4.super关键字

5.初始化顺序

6.final关键字

引言

面向对象三大特性:封装,继承和多态。今天我们就来聊聊继承。

1.继承

1.1为什么需要继承

因为我们在创建类时可能会大量用到重复的字段和方法,为了解决这个问题,面向对象思想中提出了继承的概念,专门用来进行共性抽取,实现代码复用。

1.2继承的语法

继承需要使用到extends关键字

java 复制代码
修饰符 class 子类 extends 父类{
// 主体
}

2.子类访问父类的成员变量

子类继承了父类的方法和字段,子类在方法中就可以直接访问父类的成员吗?

2.1子类和父类不存在同名成员变量

java 复制代码
class Base {
    public int a = 1;
    public int b = 2;

}
class Derievd extends Base{
    public int c = 3;

    public void func() {
        System.out.println(this.a);// 访问从父类中继承下来的a
        System.out.println(this.b);// 访问从父类中继承下来的b
    }
}
public class Test {
    public static void main(String[] args) {
        Derievd derievd = new Derievd();
        derievd.func();
    }
}

运行结果:

2.2子类和父类成员变量同名

代码如下:

java 复制代码
class Base {
    public int a = 1;
    public int b = 2;

}
class Derievd extends Base{
    public int c = 3;
    public int a = 100;

    public void func() {
        System.out.println(this.a);//访问子类自己新增加的a
        System.out.println(this.b);//访问从父类中继承下来的b
    }
}
public class Test {
    public static void main(String[] args) {
        Derievd derievd = new Derievd();
        derievd.func();
    }
}

运行结果:

得出结论:

当子类和父类成员同名时,优先访问子类自己的成员。

特性:遵循就近原则,子类有的优先使用自己的,没有再去父类中找。

2.3如果一定要访问父类的成员怎么做?

方法1:使用super关键字

方法2:初始化一个父类对象,用父类对象的引用访问父类的成员变量。

java 复制代码
class Base {
    public int a = 1;
    public int b = 2;

}
class Derievd extends Base{
    public int c = 3;
    public int a = 100;

    //子类当中 如何访问父类的成员
    public void func() {
        //方法1
        System.out.println("父类的a: "+super.a);
        System.out.println(this.a);
        //方法2
        Base base = new Base();
        System.out.println(base.a);
    }
}
public class Test {
    public static void main(String[] args) {
        Derievd derievd = new Derievd();
        derievd.func();
    }
}

执行结果:

3子类中访问父类的成员方法

3.1成员方法名字不同

java 复制代码
class Base {
    public void methodA(){
        System.out.println("Base中的methodA()");
    }
}
class Derived extends Base{
    	public void methodB(){
    	System.out.println("Derived中的methodB()方法");
    }

    public void func(){
    	this.methodB();  // 访问子类自己的methodB()
    	this.methodA();  // 访问父类继承的methodA()
    }
}
public class Test {
    public static void main(String[] args) {
        Derived derived = new Derived();
        derived.func();
    }
}

执行结果:

3.2成员方法名字相同

java 复制代码
class Base {
    public void methodA(){
        System.out.println("Base中的methodA()");
    }
}
class Derived extends Base{
    public void methodA(){
    	System.out.println("Derived中的methodA()方法");
    }

    public void func(){
    	this.methodA();  // 访问子类自己的methodA()
    }
}
public class Test {
    public static void main(String[] args) {
        Derived derived = new Derived();
        derived.func();
    }
}

执行结果:

结论:【和成员变量同名时相同】

当子类和父类成员同名时,优先访问子类自己的成员。

特性:遵循就近原则,子类有的优先使用自己的,没有再去父类中找。

3.3如果一定要访问父类的成员怎么做?

【和上面的方法相同】

方法1:使用super关键字

方法2:初始化一个父类对象,用父类对象的引用访问父类的成员变量。

java 复制代码
class Base {
    public void methodA(){
        System.out.println("Base中的methodA()");
    }
}
class Derived extends Base{
    public void methodA(){
        System.out.println("Derived中的methodA()方法");
    }

    public void func(){
        //方法1
        super.methodA();  // 访问子类自己的methodA()
        //方法2
        Base base = new Base();
        base.methodA();
    }
}
public class Test {
    public static void main(String[] args) {
        Derived derived = new Derived();
        derived.func();
    }
}

执行结果:

4.super关键字

因为子类可能会和父类成员同名,如果明确要访问父类的成员,就需要使用super关键字。

java 复制代码
public void testExtends(){
    super.name = "zhangsan";//访问从父类继承下来的成员变量
    super.age = 18;//访问从父类继承下来的成员变量
    super.eat();///访问从父类继承下来的成员方法

    color = "黄色";//访问子类自己的成员变量
    run();//访问子类自己的成员方法
}

4.1子类构造方法

在继承性关系下,构造子类对象时,需要先调用基类构造方法,然后执行子类的构造方法。
即先要把继承于父类的成员初始化完,才能初始化子类自己的成员。

java 复制代码
class Animal {
    String name;
    int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class Dog extends Animal{

    String color;

    public Dog(String name, int age,String color) {
        super(name, age);
        this.color = color;
    }
}

注意事项:

  1. 若父类无显示构造方法(没写构造方法)或默认构造方法(即无参数构造方法),子类构造方法第一行默认有隐藏的super()调用,即调用子类构造方法时,先调用基类的构造方法。
  2. 若父类构造方法有带参数,子类构造方法需要自己定义super()。
  3. 在子类构造方法中,super()必须是第一条语句。
  4. 在子类构造方法中,super()只能出现一次,并且不能和this()同时出现。

第四点解释,当我们重载子类构造方法时,this()调用,会调用重载的子类构造方法。而this()和super()在构造方法中,都必须是第一条语句,所有不能同时出现。

代码如下:

java 复制代码
public class Dog extends Animal{

    String color;

    //方法的重载
    public Dog() {
        this("green");//调用带有一个参数的构造方法
        System.out.println("使用了不带参数的构造方法");
    }

    public Dog(String color) {
        this.color = color;
        System.out.println("使用了带有一个参数的构造方法");
    }

    public static void main(String[] args) {
        Dog dog = new Dog();//调用无参构造方法
        System.out.println(dog.color);

        System.out.println("==============");
        Dog dog1 = new Dog("red");//调用带有一个参数的构造方法
        System.out.println(dog.color);
    }
}

运行结果:

4.2super和this

super和tthis都可以在成员方法中用来访问:成员变量和调用其他成员方法,都可以作为构造方法的第一条语句。

【相同点】
1.都只能在类的非静态方法中使用,用来访问非静态成员变量和调用其他成员方法。
2.在构造方法中调用时,必须是构造方法的第一条语句,并且不能同时存在。

【不同点】
1,this是当前对象的引用,当前对象即调用实例方法的对象,super相当于子类对象从父类继承下来的部分成员的引用。
2.在非静态成员方法中,this用来访问本类的方法和属性,super用来访问从父类继承下来的方法和属性。
3.在构造方法中:this()用于调用本类的构造方法,super()用于调用父类的构造方法,两者在构造方法中不能同时存在。
4.在继承体系下,构造方法中一定会存在super()调用,用户没有写编译器也会自动增加,但this()用户不写则没有。

5.初始化顺序

5.1没有继承关系时的执行顺序

我们再来回顾下初始化执行顺序,没有继承关系时的执行顺序:

java 复制代码
class Person {
    public String name;
    public int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("构造方法执行");
    }
    {
    System.out.println("实例代码块执行");
     }
    static {
    System.out.println("静态代码块执行");
     }
}

public class Test {
    public static void main(String[] args) {
        Person person1 = new Person("bit",10);
        System.out.println("============================");
        Person person2 = new Person("gaobo",20);
    }

}

运行结果:

结论分析:
1.被static修饰的静态代码块先执行,并且只执行一次,在类的加载阶段执行。
2.当有对象创建时,才会执行实例代码块,执行完实例代码块,最后执行构造方法。

5.1继承关系下的执行顺序

java 复制代码
class Person {
    public String name;
    public int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("构造方法执行");
    }
    {
    System.out.println("实例代码块执行");
     }
    static {
    System.out.println("静态代码块执行");
     }
}

class Student extends Person{
    public Student(String name,int age) {
    super(name,age);
    System.out.println("Student:构造方法执行");
     }
     {
    System.out.println("Student:实例代码块执行");
     }

     static {
    System.out.println("Student:静态代码块执行");
     }
}

public class Test {
    public static void main(String[] args) {
        Student student1 = new Student("张三",19);
        System.out.println("===========================");
        Student student2 = new Student("gaobo",20);
    }
}

执行结果:

结论分析:
1.父类静态代码块先执行,执行完再执行子类静态代码块。
2.父类实例代码块和构造方法先执行。
3.再执行子类实例代码块和构造方法。
4.静态代码块只执行一次。

6.final关键字

final可以用来修饰变量、成员方法和类。

1.被final修饰的变量或字段,表示常量,不能再被改变。

java 复制代码
final int a = 10;
a = 20;  // 编译出错

2.被final修饰的类,不能被继承

java 复制代码
final class Person {
}
class Student extends Person{
}

3.被final修饰的方法,不能重写

java 复制代码
class Person {
    public final void eat(){
         System.out.println("正在吃饭。。。");
     }
}

class Student extends Person{
    public void eat(){
        System.out.println("zhangsan正在吃饭。。。");
    }
}
相关推荐
2022.11.7始学前端3 小时前
n8n第七节 只提醒重要的待办
前端·javascript·ui·n8n
SakuraOnTheWay3 小时前
React Grab实践 | 记一次与Cursor的有趣对话
前端·cursor
阿星AI工作室3 小时前
gemini3手势互动圣诞树保姆级教程来了!附提示词
前端·人工智能
徐小夕4 小时前
知识库创业复盘:从闭源到开源,这3个教训价值百万
前端·javascript·github
ZouZou老师4 小时前
C++设计模式之适配器模式:以家具生产为例
java·设计模式·适配器模式
xhxxx4 小时前
函数执行完就销毁?那闭包里的变量凭什么活下来!—— 深入 JS 内存模型
前端·javascript·ecmascript 6
StarkCoder4 小时前
求求你试试 DiffableDataSource!别再手算 indexPath 了(否则迟早崩)
前端
fxshy4 小时前
Cursor 前端Global Cursor Rules
前端·cursor
红彤彤4 小时前
前端接入sse(EventSource)(@fortaine/fetch-event-source)
前端
曼巴UE54 小时前
UE5 C++ 动态多播
java·开发语言