面向对象基础-继承04(好坏、super、构造方法、成员方法、重写、隐显式子类初始化)

本文围绕Java继承展开,介绍了继承的好处、弊端、访问特点等内容。重点讲解了子类对象的隐式和显式初始化,隐式初始化由JVM自动调用,显式初始化需程序员手动操作。还阐述了super和this关键字的使用及区别,总结了子类构造方法中super和this的使用规则。

继承概述

在这里插入图片描述
Fu

public class Fu {
    public void show() {
        System.out.println("show方法被调用");
    }
}

Zi

public class Zi extends Fu {
    public void method() {
        System.out.println("method方法被调用");
    }
}

Demo

/*
    测试类
 */
public class Demo {
    public static void main(String[] args) {
        //创建对象,调用方法
        Fu f = new Fu();
        f.show();

        Zi z = new Zi();
        z.method();
        z.show();
    }
}

在这里插入图片描述

继承的好处和弊端

在这里插入图片描述

继承的访问特点

在这里插入图片描述

super

在这里插入图片描述
在这里插入图片描述

super内存图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

继承中构造方法访问特点

在这里插入图片描述
Fu

public class Fu {

    /*
    public Fu() {
        System.out.println("Fu中无参构造方法被调用");
    }
    */

    public Fu() {}

    public Fu(int age) {
        System.out.println("Fu中带参构造方法被调用");
    }

}

Zi

public class Zi extends Fu {

    public Zi() {
//        super();
//        super(20);
        System.out.println("Zi中无参构造方法被调用");
    }

    public Zi(int age) {
//        super();
//        super(20);
        System.out.println("Zi中带参构造方法被调用");
    }

}

Demo

/*
    测试类
*/
public class Demo {
    public static void main(String[] args) {
        //创建对象
        Zi z = new Zi();

        Zi z2 = new Zi(20);
    }
}

在这里插入图片描述

继承中成员方法访问特点

在这里插入图片描述
Fu

public class Fu {

    public void show() {
        System.out.println("Fu中show()方法被调用");
    }

}

Zi

public class Zi extends Fu {

    public void method() {
        System.out.println("Zi中method()方法被调用");
    }

    public void show() {
        super.show();
        System.out.println("Zi中show()方法被调用");
    }
}

Demo

/*
    测试类
 */
public class Demo {
    public static void main(String[] args) {
        //创建对象,调用方法
        Zi z = new Zi();
        z.method();
        z.show();
        //报错
//        z.test();
    }
}

在这里插入图片描述

继承中注意事项

在这里插入图片描述

方法重写

在这里插入图片描述
Phone

/*
    手机类
 */
public class Phone {
    public void call(String name) {
        System.out.println("给" + name + "打电话");
    }
}

NewPhone

/*
    新手机
 */
public class NewPhone extends Phone {

    /*
    public void call(String name) {
        System.out.println("开启视频功能");
//        System.out.println("给" + name + "打电话");
        super.call(name);
    }
    */

    @Override
    public void call(String name) {
        System.out.println("开启视频功能");
//        System.out.println("给" + name + "打电话");
        super.call(name);
    }

}

PhoneDemo

/*
    测试类
 */
public class PhoneDemo {
    public static void main(String[] args) {
        //创建对象,调用方法
        Phone p = new Phone();
        p.call("林青霞");
        System.out.println("--------");

        NewPhone np = new NewPhone();
        np.call("林青霞");
    }
}

在这里插入图片描述

方法重写注意事项

在这里插入图片描述
Fu

public class Fu {

    private void show() {
        System.out.println("Fu中show()方法被调用");
    }

    /*
    public void method() {
        System.out.println("Fu中method()方法被调用");
    }
    */

    void method() {
        System.out.println("Fu中method()方法被调用");
    }
}

Zi

public class Zi extends Fu {

    /*
    @Override
    private void show() {
        System.out.println("Zi中show()方法被调用");
    }
    */

    /*
    @Override
    public void method() {
        System.out.println("Zi中method()方法被调用");
    }
    */

    @Override
    public void method() {
        System.out.println("Zi中method()方法被调用");
    }
}

案例

在这里插入图片描述
在这里插入图片描述

Animal

public class Animal {
    private String name;
    private int age;

    public Animal() {
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Cat


public class Cat extends Animal {

    public Cat() {
    }

    public Cat(String name, int age) {
        super(name, age);
    }
    
    public void catchMouse() {
        System.out.println("猫抓老鼠");
    }
}

Dog

public class Dog extends Animal {

    public Dog() {
    }

    public Dog(String name, int age) {
        super(name, age);
    }

    public void lookDoor() {
        System.out.println("狗看门");
    }
}

AnimalDemo

/*
    测试类
 */
public class AnimalDemo {
    public static void main(String[] args) {
        //创建猫类对象并进行测试
        Cat c1 = new Cat();
        c1.setName("加菲猫");
        c1.setAge(5);
        System.out.println(c1.getName() + "," + c1.getAge());
        c1.catchMouse();

        Cat c2 = new Cat("加菲猫", 5);
        System.out.println(c2.getName() + "," + c2.getAge());
        c2.catchMouse();

        System.out.println("-----");
        Dog dog = new Dog();
        dog.setAge(2);
        dog.setName("旺旺");
        System.out.println(dog.getName()+","+dog.getAge());
        dog.lookDoor();

        Dog dog2 = new Dog("嘻嘻", 5);
        System.out.println(dog2.getName()+","+dog2.getAge());
        dog2.lookDoor();


    }
}

在这里插入图片描述

显隐式子类初始化

接下来重点学习一下两种方式

子类对象的隐式初始化(implicit)

隐式初始化,JVM自动调用,无需我们手动操作

条件为

  • 父类中有默认的构造方法

    • 子类的构造器中没有显式调用父类的构造方法
  • 达成上述两个条件,则JVM在初始化子类对象时进行隐式初始化

    • 永远先执行父类的构造方法,顺序为
      • 最上层的父类(Object)
      • 其他父类(继承链中越处于上流越先执行)
    • 所有父类的构造方法都执行完毕,开始执行子类构造方法

需要注意的是

  • 隐式初始化,JVM总是调用父类的无参构造,如果父类没有,就要报错
  • Object类也有默认无参
  • 隐式初始化总是不传参数,如果我们想要对参数进行赋值,就必须使用显式的子类初始化

子类对象的显式初始化(Explicit )

显式初始化,需要程序员手动写代码,告诉JVM调用哪个父类构造器

如何使用?

  • 必须在子类构造器的第一行,显式的调用父类构造方法,那么如何调用父类构造器?

    • 使用super关键字调用

    • 语法

      super(父类构造器参数);
      

什么是super关键字?

  • super代表当前类的父类的引用
  • this代表当前类的对象
  • 两者的使用没有明显差别,只是
    • this在当前类中不受访问权限控制,super访问父类成员,受访问权限控制
    • 因为当前类中即便是private仍然可以访问,但是super就不在当前类中了
this VS super  

this关键字:表示当前对象的引用         super关键字:super代表父类对象的引用

this调用当前类中定义的构造方法:this(实参列表)          
super调用父类中定义的构造方法:super(实参列表)

this访问当前对象的成员变量值          super访问父类对象中,成员变量的值

this访问当前对象的成员方法            super访问父类对象,成员方法

super与this关键字

this关键字概念:

this代表所在类的对象引用。

记住: 方法被哪个对象调用,this就代表哪个对象。

1.super可以在子类中 调用父类中名称相同的 成员方法和成员变量

2.this可以在方法中调用 类中的与方法内局部变量名称相同 的成员方法和成员变量

3.super和this的区别

(a).this 代表当前类的对象

代表对象的内存空间标识(用来存储当前类定义的内容,成员变量、方法)

(b).super (代表父类对象) 可以这么理解,实际并不代表父类对象

代表对象的内存空间的标识(用来存储父类定义的内容,成员变量、方法)

使用场景:

当局部变量和成员变量名字相同时用this,子类变量和父类变量名字相同时用super

super用法:(this和super均适用)

1.访问成员变量

this.成员变量 super.成员变量 (局部变量直接调用不需要修饰符)

2.访问构造方法

this(…) super(…) 如果是有参方法,()里面写参数

3.访问成员方法

this.成员方法() super.成员方法()

super和this使用情况内存图

1.main方法入栈,建立一个Son类型变量son,然后在堆上创建Son类型对象new Son()

2.对象的内存空间有两个标识,this空间存储子类的成员变量num1=10,num2=20,super空间存储父类变量num1=1,num2=2;

son调用show方法,show()入栈,它的局部变量为num1=100,num2=200;,调用不同的变量需要在变量名前加上标识符,如super.num1, this.num2

隐式子类对象创建:

​ 条件:

​ a. 当父类提供了默认的构造函数(无参构造方法)

​ b. 子类的构造方法中, 没有显式调用父类的其它构造方法

​ 结果:

​ JVM自动在子类构造方法第一句加上 “ super() “

​ 在执行子类的构造方法之前,JVM会自动执行父类

显式子类对象创建:

​ 程序员写代码告诉JVM在调用子类构造器之前调用父类构造方法

​ 可以在子类构造器的第一行使用super关键字,调用父类的构造方法

总结:

1,无论是隐式还是显式,最终都是为了保证父类构造器先于子类执行

​ 2,若父类中不存在默认构造方法,则必须在子类构造方法中使用super关键字调用父类构造器

​ 3,在子类构造方法中,super语句必须在第一行

​ 4,在子类构造方法中,也可以用this调用自身构造,也必须在第一行

​ 5,this和super不能共存

​ 6,构造代码块和静态代码块也是“先父后子”

为什么this和super都必须在第一行?

​ 因为子类构造器第一行永远都有一个super关键字调用,如果你自己的super和this不在第一行,会形成循环

分析程序:

public class Demo {
    public static void main(String[] args) {
        PrimaryStudent primaryStudent = new PrimaryStudent(666,888,"hello");
        System.out.println(primaryStudent.psVar);
    }
}
class Person {
    public Person() {
        System.out.println("Person类的无参构造");
    }
}
class Student extends Person {
    int sVar;
    String sVarString;
    public Student() {
        System.out.println("Student类无参构造");
    }
    public Student(int sVar) {
        System.out.println("Student int构造方法");
        this.sVar = sVar;
    }
    public Student(int sVar, String sVarString) {
        this(sVar);
        System.out.println("Student int String构造方法");
        this.sVarString = sVarString;
    }
}
class PrimaryStudent extends Student {
    int psVar = 10;
    public PrimaryStudent(int psVar, int sVar, String sVarString) {
        super(sVar, sVarString);
        System.out.println("PrimaryStudent类的 三参构造");
        this.psVar = psVar = 100;
    }
}
ends Student {
    int psVar = 10;
    public PrimaryStudent(int psVar, int sVar, String sVarString) {
        super(sVar, sVarString);
        System.out.println("PrimaryStudent类的 三参构造");
        this.psVar = psVar = 100;
    }
}

输出:

Person类的无参构造
Student int构造方法
Student int String构造方法
PrimaryStudent类的 三参构造
100

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值