大学生入门:this 和 super 关键字

一、this

什么是 this?

        this 是 java 中的一个关键字,它代表当前对象的引用

        简单来说

        this 就是汉字中的 “ 我 ”

我们先来看看它有哪些用法:

1、this 五种基本用法

1> 区分成员变量和局部变量

        这是 this 最常见的用法

        当 成员变量局部变量 同名

        用 this 明确指定访问的是成员变量

public class Student {
    private String name; // 成员变量
    
    public void setName(String name) { // 参数name是局部变量
        this.name = name; // this.name指成员变量,name指参数
    }
}

就好比你有一只小狗

当你说“小狗”的时候,可能指的是你的小狗,也可能指别的小狗

这时如果你说的是“我的小狗”,那这就显而易见了

2> 调用当前类的构造方法

        this() 可以在构造方法中调用同一个类的其他构造方法

public class Dog {
    private String breed;
    private int age;
    
    public Dog() {
        this("未知品种", 0); // 调用另一个构造方法
    }
    
    public Dog(String breed, int age) {
        this.breed = breed;
        this.age = age;
    }
}

点餐时,你可以说“我要和隔壁桌一样的套餐”,而不需要重复说一遍套餐内容。

3> 返回当前对象

        在方法中返回 this 可以返回当前对象的引用,常用于方法链式调用  

public class Book {
    private String title;
    private String author;
    
    public Book setTitle(String title) {
        this.title = title;
        return this; // 返回当前对象
    }
    
    public Book setAuthor(String author) {
        this.author = author;
        return this; // 返回当前对象
    }
}

// 使用方式
Book book = new Book().setTitle("Java编程").setAuthor("张三");

就像你在填写一张表格时,填完一项后把表格递回给你,让你继续填写下一项。

4> 作为参数传递

        可以将当前对象作为参数传递给其他方法

public class Person {
    private String name;
    
    public void introduce() {
        printInfo(this); // 把当前对象传递给方法
    }
    
    private void printInfo(Person p) {
        System.out.println("我叫" + p.name);
    }
}

类似于你拿着自己的身份证去办理业务,把“自己”的信息交给工作人员

5> this 调用方法的三种场景

①调用本类普通方法

        在类内部方法相互调用时使用

class Calculator {
    void add(int a, int b) {
        System.out.println(a + b);
    }
    
    void calculate() {
        this.add(5, 3); // 显式调用本类方法
    }
}
②实现方法链式调用

        即刚才提到的“返回当前对象”

③区分父子类方法

        当子类重写父类方法时,可用 this 明确调用本类实现

2、内存图解

public static void main(String[] args){
    Student stu1 = new Student("jack",21);
    stu1.sayHello();
 
    Student stu2 = new Student("Tom".18);
    stu2.sayHello();
}

显而易见,this 指向的是堆内存中的 对象 本身。

 

3、构造方法中 this 的正确使用

        在 java 中,构造方法中正确使用 this 关键字主要涉及两种场景:

        调用同类其他构造方法

        区分成员变量与参数(前面提到过,这里就不讨论了)

——调用同类其他构造方法

        使用 this 可以在一个构造方法中调用同类中的另一个构造方法,这种调用必须放在构造方法的第一行


public class Person {
    private String name;
    private int age;
    
    // 无参构造方法
    public Person() {
        this("无名氏", 0); // 调用有参构造方法
    }
    
    // 单参构造方法
    public Person(String name) {
        this(name, 0); // 调用有参构造方法
    }
    
    // 全参构造方法
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

二、super

什么是 super 呢?

        super 也是 java 的关键字,代表当前对象的直接父类部分

1、super 的三种核心用法

①访问父类成员变量

        当子类和父类有同名成员变量时,使用 super.变量名 可以明确指定访问父类的变量

class Parent {
    String name = "父类名称";
}

class Child extends Parent {
    String name = "子类名称";
    
    void printNames() {
        System.out.println(super.name); // 输出"父类名称"
        System.out.println(this.name);  // 输出"子类名称"
    }
}

②调用父类方法

        当子类重写父类方法后,仍可通过 super.方法名() 调用父类的原始实现

class Phone {
    void call() {
        System.out.println("基础通话功能");
    }
}

class SmartPhone extends Phone {
    @Override
    void call() {
        super.call(); // 先执行父类通话功能
        System.out.println("新增视频通话功能");
    }
}

③调用父类构造方法

        在子类构造方法中使用 super() 或 super(参数) 调用父类构造方法

class Vehicle {
    String type;
    
    Vehicle(String type) {
        this.type = type;
    }
}

class Car extends Vehicle {
    int wheels;
    
    Car(String type, int wheels) {
        super(type); // 必须放在第一行
        this.wheels = wheels;
    }
}

2、super 的正确使用

①构造方法调用必须在第一行

        super() 调用必须是子类构造方法的第一条语句

②隐式调用规则

        如果子类构造方法没有显示调用 super()

        编译器会自动插入父类无参构造方法调用

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

public class Child extends Parent{
    public Child(){
        //这里隐式提供了super();
        System.out.println("子类无参构造器")
    }
}

public class Test{
    Child c = new Child();
}

结果为:
父类无参构造器

子类无参构造器 

③继承链要求

        最终必须调用到 Object类 的构造方法(所有类的顶级父类)

这个等下我们和 this 一起使用的时候解释

④静态上下文禁用

        不能在 static 方法中使用 super

为什么呢?

看到下面的内存图大家就理解了

3、内存图解

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

    public Person(){}
}

public class Student extends Person{
    private int id;

    public Student(){}
}

public class Test{
    Student s = new Student();
} 

super 不是独立的对象,它和 this 指向同一个对象的不同部分 

上一期我们提到了,static 不依赖对象,所以没有this

而现在 super 指向的是 this 指向的一部分,连 this 没有,哪来的 super 呢?

所以 static 中也不能使用 super

三、this 和 super 的构造方法调用规则

1、基本调用规则

①必须作为构造方法的第一条语句

②二者不能同时存在

        基于第一条规则,如果二者同时出现

        就会左右脑互搏

        谁都想占据第一行的位置

③隐式 super() 调用

        如果子类构造方法没有显式调用 this() 或 super() ,编译器会自动插入父类无参构造方法的 super() 调用

2、详细执行机制

        当构造方法中使用 this() 调用本类其他构造方法时,编译器就不会再隐式调用 super() 了

        但是,这条调用链调用到最后时,都是由 super() 结尾,显示隐式都可以

public class Fu {
    private int f;

    public Fu(){
        //隐式调用了 super();
        System.out.println("父类的无参构造器");
    }
}

public class Zi extends Fu{
    private int z;

    public Zi(){
        System.out.println("子类的无参构造器");
    }
    public Zi(int z){
        this();
        this.z = z;
        System.out.println("子类的单参构造器");
    }
    public Zi(int f,int z){
        this(z);
        this.z = z;
        setF(f);
        System.out.println("子类的全参构造器");
    }
}

public class Test {
    public static void main(String[] args) {
        Zi z = new Zi();

        Zi z1 = new Zi(1);

        Zi z2 = new Zi(3,1);
    }
}

结果为:

        类的无参构造器
        子类的无参构造器


        父类的无参构造器
        子类的无参构造器
        子类的单参构造器

        
类的无参构造器
        子类的无参构造器
        子类的单参构造器
        子类的全参构造器

四、易踩坑的点

1、当父类没有无参构造时,必须显示调用 super() 指向父类的有参构造,或者给父类写上无参构造

// 必须确保父类有相应的构造方法
class Parent {
    Parent(String s) { } // 没有无参构造方法
}

class Child extends Parent {
    Child() {
        // super(); // 编译错误:父类没有无参构造方法
        super("default"); // 必须显式调用
    }
}

2、链式调用忘记返回 this

        要实现方法链式调用,每个方法必须都返回 this

        不要忘记写 return this;

        否则对象不能正常返回

3、多层继承中的 super 调用限制

        super 只能访问 直接父类,不能跨级访问爷爷类

4、关于 static

        再次强调,static 方法中不能使用 this 和 super

5、方法重写时忽略 super 调用

        重写方法时,若需要保留父类功能,必须调用 super.方法名();

        否则会完全覆盖父类方法,导致功能缺失

6、思维误区

        this 和 super 是同一个对象的不同视图,不是两个独立的对象

        this 指向当前对象整体,super 指向当前对象的父类部分

7、链式调用的返回值类型

        不能是void!

一般情况有三种:

①返回类本身:

public class Student {
    private String name;
    private int age;
    
    public Student setName(String name) {
        this.name = name;
        return this; // 返回当前对象
    }
    
    public Student setAge(int age) {
        this.age = age;
        return this; // 返回当前对象
    }
}

// 使用
Student student = new Student()
    .setName("张三")
    .setAge(18);

②返回父类类型

class Animal {
    public Animal eat() {
        System.out.println("动物在吃东西");
        return this;
    }
}

class Dog extends Animal {
    public Dog bark() {
        System.out.println("狗在叫");
        return this;
    }
    
    @Override
    public Animal eat() {
        super.eat();
        return this; // 可以返回this(Dog类型),但声明为Animal类型
    }
}

// 使用
Dog dog = new Dog();
Animal animal = dog.eat().eat(); // 返回的是Dog对象,但类型是Animal

③返回接口类型

interface Builder {
    Builder addElement(String element);
}

class XMLBuilder implements Builder {
    private StringBuilder xml = new StringBuilder();
    
    @Override
    public Builder addElement(String element) {
        xml.append("<").append(element).append(">");
        return this;
    }
    
    public XMLBuilder setAttribute(String attr) {
        xml.append(" ").append(attr);
        return this;
    }
}

其他特殊情况遇到了再特殊讨论

今天的分享就到这里,欢迎大家补充 斧正

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值