JavaseLearn20-this&super

JavaseLearn20-this&super

1. this

1.1什么是this?

this是一个关键字,是一个变量,是一个引用,代表的是对象本身。

1.2 this在内存上的情况

this位于堆内存的对象里,指向对象本身。

this在下面程序中的内存图如上所示。

package This;

/**
 * @Author: TSCCG
 * @Date: 2021/07/03 09:53
 */
public class ThisDemo01 {
    public static void main(String[] args) {
        //创建两个实例对象
        Student s1 = new Student("张三");
        Student s2 = new Student("李四");
        Student s3 = new Student();
        //实例对象调用Student类中方法
        s1.learn();
        s2.learn();
        s3.learn();
    }
}

/**
 * 学生类
 */
class Student {
    //实例变量
    String name;
    //有参构造
    public Student(String name) {
        this.name = name;
    }
    //无参构造
    public Student() {
        this("学生");
    }
    //实例方法
    public void learn() {
        //this.可以省略
        //如果省略,默认还是会使用this调用name
        System.out.println(this.name + "在学习。");
    }
}

1.3 this的调用

1.3.1 this只能用在实例方法上

我们把上面例子中的learn()方法拿过来:

//实例方法
public void learn() {
    //this.大部分情况下可以省略
    //如果省略,默认还是会使用this调用name
    System.out.println(this.name + "在学习。");
}

this只能用在实例方法上,谁调用它,this就代表谁。

如上面程序中两个实例对象调用learn方法,

当s1调用learn方法时,this代表的就是s1,name就是"张三";

当s2调用learn方法时,this代表的就是s2,name就是"李四"。

张三在学习。
李四在学习。

注意:

this无法在静态方法中使用,原因是this代表的是当前对象,而静态方法的调用不需要对象。

1.3.2 this可以区分局部变量和实例变量

我们把上面的例子中有参构造方法拿过来:

//有参构造
public Student(String name) {
    this.name = name;
}

this.name = name; 这行语句中,this.name代表的是对象中的实例变量,后面的name是构造方法里的局部变量,也就是形参。作用是将传过来的字符串赋给实例变量。

如果我们把this.name = name中的this.省略掉

//有参构造
public Student(String name) {
    name = name;
}

根据就近原则,两个name都代表的都会是构造方法中的局部变量,而非实例变量。这样会导致创建对象时,传入构造方法里的字符串不会赋给实例变量。

为了区分实例变量和局部变量,这里必须使用this.

1.3.3 this可以通过当前的构造方法去调用本类中的另一个构造方法

语法格式:this(实际参数列表);

例如上面例子中的无参构造方法:

//无参构造
public Student() {
    this("学生");
}

this() 这个语法的作用就是代码复用。

通过一个构造方法1去调用本类中的构造方法2,可以实现代码复用。

本例中,如果在创建对象的时候调用的是无参构造方法,那么无参构造会自动调用本类中的有参构造,将"学生"传入有参构造。

学生在学习。

注意:

  • 对于this()的调用必须位于构造方法第一行,且只能出现一次。
  • this()语法常用于设置默认值。

1.4 this总结

  1. this是一个关键字,是一个引用,保存内存地址指向对象自身。

  2. this的语法:"this." "this()"。

  3. this可以使用在实例方法和构造方法上。

  4. this出现在实例方法中时,代表的是当前对象。

  5. this不能使用在静态方法上,因为静态方法的调用不需要对象。

  6. this. 大部分情况下可以省略,但是在用于区分局部变量和实例变量时不能省略。

    public void learn(String name) {

    ​ this.name = name;

    }

  7. this()出现在构造方法中时,表示当前构造方法调用本类中的另一个构造方法,目的是代码复用。

  8. this()在构造方法中只能出现在第一行,且只能出现一次。

2. super

2.1 super概述

super和this很相似,我们可以对比this来理解super

  1. super是一个关键字,代表的是当前对象(this)的父类型特征。
  2. super的语法:"super." "super()"。
  3. super能出现在实例方法和构造方法中,不能出现在静态方法中。
  4. super. 大部分情况下可以省略,当子类和父类有相同的属性或者相同的方法,又想通过子类调用父类的属性或方法时,super不可省略。
  5. super()表示通过当前子类的构造方法调用父类的构造方法,目的是为了在创建子类对象之前先初始化父类型特征。
  6. super()在构造方法中只能出现在第一行,且只能出现一次。同一个构造方法中,this()和super()不能共存。
  7. 当一个构造方法第一行既没有this()也没有super()时,默认会有一个super();表示通过当前子类构造方法调用父类的无参构造方法。所以必须要保证父类存在无参构造方法。

2.2 super()

2.2.1 super()表示通过子类构造方法调用父类构造方法

模拟现实世界中的关系:先有父亲,才有儿子。

package Super;

/**
 * @Author: TSCCG
 * @Date: 2021/07/03 09:53
 */
public class SuperDemo01 {
    public static void main(String[] args) {
        Son s1 = new Son();
        Son s2 = new Son(20);
    }
}
/*
父类
*/
class Father {
    //父类的无参构造方法
    public Father() {
        System.out.println("父类的无参构造");
    }
    //父类的有参构造方法
    public Father(int num) {
        System.out.println("父类的有参构造" + num);
    }
}
/*
子类
*/
class Son extends Father {
	//子类的无参构造方法
    public Son() {
        //调用父类的无参构造方法
        super();
        System.out.println("子类的无参构造");
    }
    //子类的有参构造方法
    public Son(int num) {
        //调用父类的有参构造方法
        super(num);
        System.out.println("子类的有参构造" + num);
    }
}

结果:

父类的无参构造
子类的无参构造
父类的有参构造20
子类的有参构造20

2.2.2 子类构造方法默认执行super();

当一个构造方法第一行既没有this()也没有super()时,默认会有一个super();表示通过当前子类构造方法调用父类的无参构造方法。

package Super;

/**
 * @Author: TSCCG
 * @Date: 2021/07/03 09:53
 * 当一个构造方法第一行中没有this()和super()时,默认会有一个super();
 */
public class SuperDemo01 {
    public static void main(String[] args) {
        Son s1 = new Son();
    }
}
class Father {

    public Father() {
        System.out.println("父类的无参构造");
    }
}
class Son extends Father {

    public Son() {
        //默认有一个super();
        System.out.println("子类的无参构造");
    }
}

结果:

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

注意:

  • 无论如何,父类的构造方法一定会执行。
  • 在java语言中无论new什么对象,最终一定会执行顶级父类Object的无参构造方法(Object类的无参构造方法处于栈顶部,最后调用,最先执行完毕)

2.2.3 必须要保证父类存在无参构造方法

父类方法如果什么都没写,默认会有一个无参构造方法

package Super;

/**
 * @Author: TSCCG
 * @Date: 2021/07/03 09:53
 */
public class SuperDemo01 {
    public static void main(String[] args) {
        Son s1 = new Son();
    }
}
class Father {
	/*
	如果父类中什么都没有,默认给一个无参构造方法
	public Father() {
	
	}
	*/
}
class Son extends Father {

    public Son() {
        super();
        System.out.println("子类的无参构造");
    }
}

结果:

子类的无参构造

但如果此时在父类中写一个有参构造方法,则会将默认的无参构造方法覆盖,子类调用父类的无参构造方法会报错。

所以必须要保证父类存在无参构造方法。

2.2.4通过super(实参)访问父类私有属性

创建一个Father父类和一个Son子类,Son类继承Father类。

父类中有两个私有属性,分别是name和age,有一个有参的构造方法和一个无参的构造方法。

子类也有一个私有属性girlFriend,也有一个有参构造方法和一个无参构造方法。

创建一个子类对象,同时给这个子类对象中的name、age、girlFriend属性赋值。

package Super2;

/**
 * @Author: TSCCG
 * @Date: 2021/07/03 20:04
 */
public class SuperDemo01 {
    public static void main(String[] args) {
        Son s1 = new Son("张三",20,"阿珍");
    }
}
class Father {
    private String name;
    private int age;
    public Father() {

    }
    public Father(String name,int age) {
        this.name = name;
        this.age = age;
    }
}
class Son extends Father {
    private String girlFriend;
    public Son() {

    }
    public Son(String name,int age,String girlFriend) {
        /*
        this.name = name;
        this.age = age;
         */
        super(name,age);
        this.girlFriend = girlFriend;
    }
}

当我们创建子类对象并赋值时,会调用子类中有参构造方法:

public Son(String name,int age,String girlFriend) {
    /*
    this.name = name;
    this.age = age;
    */
    super(name,age);
    this.girlFriend = girlFriend;
}

通常来说,我们通过下面两个语句对实例对象进行赋值

this.name = name;
this.age = age;

但name和age都是父类中的私有属性,我们无法在子类中直接访问。

这时,我们可以调用父类中的有参构造方法来访问这两个私有属性,效果是一样的。

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

2.3 内存图描述super

下面我们用内存图来描述上一个例子中Son类型对象的的创建。

  1. 在创建过程中,Son类构造方法中调用了父类Father的构造方法,Father类的构造方法又继续向上调用Father类的父类Object的构造方法。但实际上对象只创建了一个。

  2. super代表的是当前对象(this)的父类型特征。

    • 比如,我继承了我父亲的一部分特征:

      如眼睛、头发等。

      super代表的就是"眼睛、头发等"。

      "眼睛、头发等"虽然是继承了我父亲的,但是这部分是我自己的。

  3. super(实参)的作用是:初始化当前对象的父类型特征,并不是创建新对象。

  4. super可看作是this对象的一部分,而this对象无法在静态方法中实用,故super也无法在静态方法中实用。

2.4 super.

super.可以访问父类中的属性和方法

2.4.1 super不能省略的情况

我们将上面例子中Father类中私有的属性name公有化,然后在Son类中添加一个实例方法talk()。然后通过Son类型对象调用该方法,结果会是什么呢?

package Super2;

/**
 * @Author: TSCCG
 * @Date: 2021/07/03 20:04
 */
public class SuperDemo01 {
    public static void main(String[] args) {
        Son s1 = new Son("张三",20,"阿珍");
        s1.talk();
    }
}
class Father {
    String name;
    private int age;
    public Father() {

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

    }
    public Son(String name,int age) {
        super(name,age);
    }
    public void talk() {
        //this表示当前对象
        System.out.println(this.name);
        //super表示的是当前对象的父类型特征,是this指向的那个对象中的一块空间
        System.out.println(super.name);
        //默认调用this
        System.out.println(name);
    }
}

运行:

张三
张三
张三

我们再在Son类中添加一个同样是String类型的name,再次运行。

package Super2;

/**
 * @Author: TSCCG
 * @Date: 2021/07/03 20:04
 */
public class SuperDemo01 {
    public static void main(String[] args) {
        Son s1 = new Son("张三",20,"阿珍");
        s1.talk();
    }
}
class Father {
    String name;
    private int age;
    public Father() {

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

    }
    public Son(String name,int age) {
        super(name,age);
        //name = null;
    }
    public void talk() {
        System.out.println(this.name);
        System.out.println(super.name);
        System.out.println(name);
    }
}

结果:

null
张三
null

为什么会出现这样的结果呢?

在Son类的有参构造方法中,调用了Father类的有参构造方法,给Father类的name赋了值,而这个name在内存中的位置是在Father类型特征里的,而Son类自己的name由于未赋值,默认赋值为null。

而this访问的是位于Son类型特征里的null,super访问的是Father类型特征里的"张三",所以会出现上述结果。

当子类和父类有相同的属性或者相同的方法,又想通过子类调用父类的属性或方法时,super不可省略。

2.4.2使用super. 调用父类方法

package Super3;

/**
 * @Author: TSCCG
 * @Date: 2021/07/04 00:15
 */
public class SuperDemo02 {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.see();
    }
}
class Animal {
    public void move() {
        System.out.println("Animal move");
    }

}
class Cat extends Animal {
    @Override
    public void move() {
        System.out.println("Cat move");
    }
    public void see() {
        this.move();
        super.move();
        move();
    }
}

结果:

Cat move
Animal move
Cat move
posted @ 2021-07-04 00:21  TSCCG  阅读(46)  评论(0编辑  收藏  举报