• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Java | this和super关键字【深入理解子类和父类的继承关系】

武飞扬头像
juejin
帮助176

一、关键字介绍及引入

1、this关键字

this关键字是什么?

之前我们在讲类的static关键字时也有提到过this关键字,它可以用来访问当前对象的成员变量和成员方法

this是一个引用,是一个变量,this变量中保存了内存地址指向了自身,它存储在JVM堆内存中Java对象的内部

==有关使用格式在下面super关键字中一起说明==

2、super关键字

super关键字是什么?

对于super关键字,这个是在Java中出现的,而C 中没有,它表示子类继承父类之后可以通过这个关键字去访问父类的一些成员变量和成员方法,以及可以通过这个关键字去实现父类的构造器

this和super关键字要怎么使用(附有表格插图)

  • 有关这个,我在上面的this关键字中并没有提到具体的使用格式,这里一并说明:book:

在这里插入图片描述

  • 从上述表格我们可以很清晰的看出这两个关键字的使用方法和格式,主要是this.和this()以及super.和super()这两种方法,this.和super.主要是用于访问成员方法和成员变量,我们不做过多讲解,后面主要讲解的是this()和super()这两种如何去访问本类和父类的构造器

二、关键字的使用及分步讲解

1、this关键字

this关键字的基础应用

接下来分别来讲一下this关键字在构造方法和实例方法中的应用

public class People {
    String name;
    int leg,hand;
    People(String name){
        this.name = name;
        this.init();	//可省略
    }
    void init(){
        leg = 2;
        hand = 3;
        System.out.println(name   "有"   leg   "条腿"   hand   "双手");
    }
    public static void main(String[] args) {
        People people = new People("奥巴马");
    }
}
  • 首先是在构造方法中,从People类的有参构造中我们可以看出,不仅初始化了name成员变量,而且调用了成员方法init(),这里都是使用到了this关键字,但是这个this关键字对于成员变量和成员方法的调用时可以省略的,因为这个关键字即使你没写的话它系统中也是会默认有的
class A{
	int x;
	static int y;
	void f(){
		this.x = 100;
		A.y;
		System.out.println(this);
	}
}
  • 这里可以看到,我直接将this关键字通过输出语句打印了出来,这里代表的其实就是当前对象的地址

this关键字调用本类其他构造器

  • 有时候,我们在创建一个对象的时候,忘了去初始化其一些参数,但这些参数又是必须要有的,这个时候我们就可以去通过this(...)去默认初始化化子类的一些数据
  • 看到下面代码,我们看到是==写了三个构造器==,一个是默认无参构造器,一个是两个参数的全参构造器,但是还有一个构造器之后一个name属性,这其实也是合法的,为的就是在传参的时候若是没有传入全部的参数也可以运行,也不会出错,所以甚至你可以也只有一个schoolName这个数据去初始化
public class People {
    private String name;
    private String schoolName;

    public People(){}
    public People(String name){
        //借用本类兄弟构造器
        //super();        此处不能调用父类构造器,否则会重复调用
        this(name,"光明顶");
    }
    public People(String name, String schoolName) {
        super();
        this.name = name;
        this.schoolName = schoolName;
    }

    public String getName() {
        return name;
    }

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

    public String getSchoolName() {
        return schoolName;
    }

    public void setSchoolName(String schoolName) {
        this.schoolName = schoolName;
    }
}
  • 接下去就是使用test测试类去测试一下,首先创建第一个对象 ,初始化了姓名和学校,但是在创建第二个对象的时候,却没有去初始化其学校,但是去没有报错,而且从运行结果来看我们默认设置的学校名称初始化也成功了,张无忌在【光明顶】学习,可见这种使用的容错率很低,也比较灵活:bell:
public class Test {
    public static void main(String[] args) {
        People p1 = new People("张三丰","凌霄宝殿");
        System.out.print(p1.getName());
        System.out.println("在"   p1.getSchoolName()   "学习");

        People p2 = new People("张无忌");
        System.out.print(p2.getName());
        System.out.println("在"   p2.getSchoolName()   "学习");
    }
}

在这里插入图片描述

  • 具体的调用流出如下

在这里插入图片描述

2、super关键字

super关键字操作被隐藏的成员变量和方法

首先我们来看这个案例,初步了解super关键字的调用

//求解总和
class Sum{
    int n;
    float f(){
        float sum = 0;
        for(int i = 1;i <= n;   i)
            sum  = i;
        return sum;     //返回总和
    }
}
//求解平均值
class Average extends Sum{
    int n;
    float f(){
        float c;
        super.n = n;        //调用父类中的n,进行初始化操作
        c = super.f();      //获取总和
        return c/n;         //返回平均值
    }
    float g(){
        float c;
        c = super.f();
        return c/2;     //返回总和的一半
    }
}
public class test1 {
    public static void main(String[] args) {
        Average average = new Average();
        average.n = 100;        //初始化数据个数
        float resultOne = average.f();      // 5050/100 = 50.5
        float resultTwo = average.g();      // 5050/2 = 2525.0

        System.out.println("resultOne = "   resultOne);
        System.out.println("resultTwo = "   resultTwo);
    }
}
  • 从上述案例,我们可以看到,有一个Sum求和类,然后有一个Average求平均值类,这个类使用extends关键字继承了Sum求和类,在这个类中是,因为需要求解平均值,所以需要使用总和,因此可以直接通过super关键字去获取父类中已封装好的方法,然后在主方法中只需要传入对应的数据个数即可;以及返回总和的一半也是一样,需要调用父类的求和方法

==注:当用super调用被隐藏的方法时,该方法中出现的成员变量和被子类隐藏的成员变量或继承的成员变量==

使用super调用父类的构造方法(重点!!!)

1、子类的全部构造器默认会调用父类的默认构造器

public class Animal {
    Animal() {
        System.out.println("父类无参构造");
    }
}

class Dog extends Animal{
    Dog(){
        super();    //写不写都有,默认找父类的无参构造器
        System.out.println("子类无参构造");
    }
    Dog(String name){
        super();    //写不写都有,默认找父类的无参构造器
        System.out.println("子类有参构造");
    }
}
public class Test {
    public static void main(String[] args) {
        Dog d = new Dog();
        System.out.println(d);

        Dog d2 = new Dog("得到");
        System.out.println(d2);
    }
}

在这里插入图片描述

  • 从上面的例子我们可以看出,当使用子类去声明一个对象时,会首先调用父类的默认构造器,这个在C 中其实也是这样,无论你子类使用的是无参还是有参构造器,因为你继承了一个父类,所以会默认去调用父类的无参构造器
  • 在子类构造其中的第一行,默认会有super()这个东西,这个写不写其实都是有的,意思就是去调用父类的无参构造器,从运行结果我们也可以看出==父类的无参构造器都是执行在子类构造器之前==
  • 那有小伙伴就会问为什么,其实就是因为你子类在初始化的时候,可能会用到父类的数据,所以一定要先调用父类构造器,完成父类空间初始化,这样子类才能使用父类中的成员变量和成员方法

2、在子类中可以使用super去调用父类的有参构造器

  • 比如这里有一个People类,里面有它的两个成员变量name和age,以及它们的一些get、set方法和构造方法
public class People {
    private String name;
    private int age;

    public People(){}

    public People(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;
    }
}
public class Test2 {
    public static void main(String[] args) {
        Teacher t = new Teacher("刘德华",50);
        System.out.println(t.getName());
        System.out.println(t.getAge());
    }
}
public class Teacher extends People{
    public Teacher(String name,int age){
        super(name,age);
    }
}
  • 接着我这里有一个测试类需要创建一个老师对象,传入其姓名和年龄,但是通过Teacher老师类来看,其并没有自己的独属的成员变量,只有继承自父类的一些功能,那要怎么去初始化其姓名和年龄呢?
  • 当我们不知道super关键字的时候,我们可能回去这么做,就如下面代码所示,但是这样写是无法初始化子类数据的,因为子类中根本就没有name 和 age属性,要初始化子类的这个数据,必须将其传入到父类中,==通过调用父类的有参构造去初始化子类的数据==,具体的初始化数据如下图所示:point_down:

在这里插入图片描述

public class Teacher extends People{
    public Teacher(String name,int age){
        this.name = name;
        this.age = age;
    }
}
  • 但是有一点要注意的是,如果你只是使用super()去调用父类中的构造器,那么我们在上面讲到过,会默认调用父类的无参构造器,但如果这时候父类中没有给出无参构造器的话,就会报错,这时候程序就会出问题,那如何解决呢?:mag:
  • 这个很简单,我们只要通过手写super(...),去调用父类的有参构造,就没事了,或者更加安全一点就是在父类中给出无参构造器,这样的话无论别人是是用的super()或是super(...),都不会出问题

三、在使用this(...)和super(...)时的注意事项

  • 子类通过this(...)去调用本类的其他都早起,本类的其他构造器会通过super去手动调用父类构造器,最终还是会调用父类构造器的
  • 注意:this(...)和super(...)都只能放在构造器的第一行,所以二者不能共存在同一个构造器中

我们到通过具体代码的分析来看一下:mag:

在这里插入图片描述

在这里插入图片描述

四、总结和回顾

在本文中,我们讲解了Java中的this和super两个关键字,知晓了其基本概念以及如果通过两种方式this.和this(...)去调用子类中的变量和方法以及本类兄弟构造器,使用super.和super(...)通过子类去访问父类中的成员变量和成员方法,以及父类的构造器,较extends关键字更加深入地理解了子类和父类的继承关系,也对类和对象的第二大特性——继承有了一个完整的知识体系

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanegck
系列文章
更多 icon
同类精品
更多 icon
继续加载