【Java】探究super本质

目录

一、super用法介绍

1. 访问父类的成员变量

2. 调用父类的方法

3. 调用父类的构造方法

二、super本质理解


一、super用法介绍

在Java中,super是一个关键字,主要用于访问父类的成员(方法、构造函数、变量)。它在继承的上下文中非常重要,以下是super的常见用法和场景

1. 访问父类的成员变量

如果子类和父类中存在同名的成员变量,子类可以通过super关键字来访问父类的成员变量。

class Parent {
    int num = 10;
}

class Child extends Parent {
    int num = 20;

    void display() {
        System.out.println(num); // 输出子类的num,结果为20
        System.out.println(super.num); // 输出父类的num,结果为10
    }
}

2. 调用父类的方法

如果子类和父类中存在同名的方法,子类可以通过super关键字来调用父类的方法。

class Parent {
    void show() {
        System.out.println("Parent show");
    }
}

class Child extends Parent {
    void show() {
        System.out.println("Child show");
    }

    void display() {
        show(); // 调用子类的show方法,输出Child show
        super.show(); // 调用父类的show方法,输出Parent show
    }
}

3. 调用父类的构造方法

在子类的构造方法中,若没有显式调用父类的构造方法,则会隐式调用,相当于在子类构造函数的第一行加上super(),但这样的方式编译器只能调用父类无参的构造函数,若想调用含参的,就需要在子类的构造方法中,通过super(参数)来显式调用父类的构造方法。

public class People
{
    protected String name;
    public People(String name)
    {
        this.name = name;
    }

}

class Student extends People
{
    private String id;

    public Student(String name, String id)
    {
        super(name);
        this.id = id;
    }
    public String toString()
    {
        return "姓名:"+name+" 学号:"+id;
    }

    public static void main(String[] args)
    {
        Student s=new Student("小明","2310");
        System.out.println(s);
    }

}

输出

二、super本质理解

说到super的本质,现在学术界主要有两种观点:第一种,super是对象引用,表示父类对象;第二种,super是一种关键字,与父类对象没有直接关系,只是能够实现一些特定功能。

下面我将带着你逐渐揭开super的真面目

我们先来看几个真实的对象引用的例子,以下s变量是真实学生对象的引用

public class People
{
    public String name;
    public People(String name)
    {
        this.name = name;
    }

}

class Student extends People
{
    private String id;

    public Student(String name, String id)
    {
        super(name);
        this.id = id;
    }
    public String toString()
    {
        return "姓名:"+name+" 学号:"+id;
    }
    public String getId()
    {
        return id;
    }
    public static void main(String[] args)
    {
        Student s=new Student("小明","2310");//此处s是学生对象的引用,即“管理者”
        System.out.println(s.name);//成员变量,输出小明
        System.out.println(s.getId());//成员函数,输出2310
        System.out.println(s);//输出姓名:小明 学号:2310
    }

}

运行结果

 

乍一看,上面几个例子中,super不也是这样吗,super.num,super.show(),甚至在显式调用父类构造函数的时候写的也是super(name),这不就跟People(name)一样吗,所以super是父类对象引用

先说结论,super不是父类对象的引用,而只是一个关键字,其中存储了指向父类部分的地址,使之能够完成与父类相关的操作

我们来看证据

(1)我们知道,在Java中,任何对象都是Object类的子类,那么根据向上造型(上转型),任何对象应该都可以“赋值”给Object,即由Object父类管理,如上一个例子,就可以这样写

Object s=new Student("小明","2310");

或这样

Student s=new Student("小明","2310");
Object o=s;

 经过测试,这都是没问题的,只是这样一来s只能使用Object父类的东西(这里牵扯到上转型的知识点,与我们的问题无关,不再赘述)

那么,如果super是父类对象的引用, 它也应该可以这样写

public Student(String name, String id)
{
    super(name);
    Object o=super;
    this.id = id;
}

但是实际上这是不行的,编译都过不去

报错

编译器必须让你加个“.” ,也就是super.name这样的形式才行,可见,super并不是父类对象的引用(2)这部分与(1)类似,这次我们通过toString方法来区别对象引用和super关键字

我们知道,Object类中有一个toString函数,用来描述对象的信息,则对于Object类的子类,若不重写toString函数,使用System.out.println时输出的会是 类名@哈希码 这样的形式,重写后则会根据你的想法输出对象相关的信息

先看真实对象引用,这里我重写了toString函数

public class People
{
    public String name;
    public People(String name)
    {
        this.name = name;
    }
}

class Student extends People
{
    private String id;
    public Student(String name, String id)
    {
        super(name);
        this.id = id;
    }
    public String toString()
    {
        return "姓名:"+name+" 学号:"+id;
    }
    public static void main(String[] args)
    {
        Student s=new Student("小明","2310");//此处s是学生对象的引用,即“管理者”
        System.out.println(s);//输出姓名:小明 学号:2310
    }
}

那么,super是不是也能通过println函数输出呢?我们来试一下

public Student(String name, String id)
{
    super(name);
    System.out.println(super);
    this.id = id;
}

 

可见,也是不行的这再次证明了,super不是父类对象的引用

(3) 在结论中我说,super中存储了指向父类部分的地址,使之能够完成与父类相关的操作,这如何证明?

如果你学过c语言,拿指针的概念来理解super会很合适,我们来看例子

还是上面那个People和Student的例子,我在构造函数中加了一个断点,我们来看调试

 

可见,super和this的首地址是一样的

 

可见,super.name和this.name地址相同,是一个唯一的name

由此,我们可以做一些合理的推断

Student对象在内存中的情况如下

可见,super可以理解为一个指针,其中存储了子类中父类部分的地址(不是对象,子类对象中没有父类对象),因此,通过这个地址,super就可以直接访问到父类的成员变量和方法,上述的例子也就不难理解了,然而,作为一个地址的“存储器”,super不能作为对象赋值和输出也情有可原了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值