问:简单说说 Java 中 this 和 super 的区别和应用场景?
答:this 为当前类的引用对象,谁调用代表谁;super 为父类存储空间标识,可以理解为父类对象,谁调用代表谁的父亲。
对于 this 的应用场景主要分下面几类:
构造方法:通过 this 调用同类中另一个满足指定参数类型的构造方法的用发是 this(参数列表); 这个仅仅在类的构造方法中,别的地方不能这么用,同时要注意 this(参数列表); 语句只能用在子类构造方法体中的第一行。
变量:函数参数或者函数中的局部变量和成员变量同名的情况下成员变量被屏蔽,此时要访问成员变量则需要用 this.成员变量名; 的方式来引用成员变量,在没有同名的情况下可以直接用成员变量的名字而不用 this。
函数:在函数中需要引用该函所属类的当前对象时候可以直接用 this,特别注意,this 不能用在 static 方法中,因为 static 方法是类级别的,this 是对象级别的。
对于 super 的应用场景主要分下面几类:
构造方法:在子类构造方法中要调用父类的构造方法可以用 super(参数列表); 的方式调用,参数不是必须的,同时要注意 super(参数列表); 语句只能用在子类构造方法体中的第一行。
变量:当子类方法中局部变量或子类成员变量与父类成员变量同名(即子类局部变量覆盖父类成员变量)时用 super.成员变量名; 来引用父类成员变量,如果父类的成员变量没有被覆盖也可以用 super.成员变量名; 来引用父类成员变量,只是多此一举。
成员方法:当子类成员方法覆盖父类成员方法(子类和父类有完全相同的方法定义)时用 super.方法名(参数列表); 的方式访问父类方法。
注意:this 和 super 不能同时出现在一个构造函数里面,因为 this 必然会调用其它的构造函数,其它的构造函数必然也会有 super 语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过;此外由于 this 和 super 都指的是对象,所以均不可以在 static 中使用(包括 static 变量、static 方法、static 语句块)。
问:为什么构造方法里 this 或者 super 函数调用必须放在第一行且无法共存?
答:super 方法在构造函数的第一行原因是子类有可能访问了父类对象,比如在构造函数中使用父类对象的成员函数和变量,在成员初始化使用了父类,在代码块中使用了父类等,所以放在第一行可以保证在子类可以访问父类对象之前完成对父类对象的初始化。
this 方法在构造函数的第一行原因是为保证父类对象初始化的唯一性,因为假设类 B 是类 A 的子类,如果 this 方法可以在构造函数的任意行使用则首先程序运行到构造函数 B() 的第一行发现没有调用 this() 和 super(),就自动在第一行补齐了 super() 方法(这是 java 默认的机制),以此完成了对父类对象的初始化,然后返回子类的构造函数继续执行,当运行到构造函数 B() 的 this(参数) 调用行时, 调用 B 类对象的另一个构造方法 B(参数),在 B(参数) 中还会对父类对象再次初始化,这就造成了对资源的浪费,也有可能造成某些意想不到的结果,所以 this 方法不能出现在构造方法除第一行以外的其他行。
这也就解释了为什么在构造方法里面 this 与 super 方法不能同时存在的原因。
问:如下程序有什么问题吗,结果是什么?
class Base {
Base() {
System.out.println("Base");
}
}
public class Demo extends Base {
public static void main(String argv[]) {
Demo demo = new Demo();
super();
}
Demo() {
System.out.println("Demo");
}
}
答:上面的程序无法编译通过,在 IDE 中 super(); 行语句会提示 "Only constructors can invoke constructors" 错误,因为 Java 里在子类中用 super 调用父类构造函数时,调用函数必须放在子类构造函数的第一条语句位置,上面代码那种调用是完全错误的用法,即便是调用父类的普通方法也应该是 super.方法 的形式。