Java的继承能保证子类拥有父类的方法的同时,还能有自己的方法,然后也是研究了一下super和this的用法:
super的用法:
(1)、super关键字有两个用法:super()和super. ,super()这个用法,用于构造函数中,子类构造函数直接继承父类的构造函数功能,然后可以在super后再添加上子类独有的构造方法;
(2)、super能出现在实例方法和构造方法中:实例方法就是需要实例化对象后才能调用的方法,其存放于方法区,JVM在实例化对象的时候会去堆内存中开辟一块空间存储他。 实例方法只有在类实例化后才能被具象化,因为只有在此时方法才能知道其作用的对象。 更简单点说就是,实例化方法就是没有static修饰的方法; 构造方法就是实例化对象的时候调用的方法。这里引用一个知乎大佬的图,原文地址
(3)、(2)中说明super能出现的场景,自然对应的就是不能出现在什么方法中了,剩下的就是静态方法了;为什么不能出现在静态方法中呢?静态类是在类加载的时候就会初始化,static方法会存放在静态区,这个方法是属于类的,可以通过类名去访问。 但是super代表父类对象的引用,而super()表示应用父类的默认构造方法。 也就是说super存在的前提是必须有父类的对象,而在JVM加载类的时候又怎么可能存在类对象呢? 同理,this表示当前类对象的引用,那也得实例化时才有,在JVM加载类的时候是不存在的。
b)、一个不知道怎么描述的问题:
如下例子,cl_parent为父类,cl_son为子类,其中fun1和fun2为类的实例化方法,当调用子类fun1时,因为会继承父类父类fun1,但是父类fun1中又调用了fun2,那么此时是调用父类fun2还是子类fun2呢?
public class HelloWorld{
public static void main(String[] args){
//cl_parent cp1 = new cl_parent();
cl_son cs1 = new cl_son();
cs1.fun1(0, 0);
}
}
class cl_parent {
int num1;
int num2;
public cl_parent(){
System.out.println("here is parent's construction");
}
void fun1(int a, int b){
num1 = a;
num2 = b;
fun2();
System.out.println("here is parent's fun1");
}
void fun2(){
System.out.println("here is parent's fun2");
}
}
class cl_son extends cl_parent{
public cl_son(){
System.out.println("here is son's construction");
}
void fun1(int a, int b){
super.fun1(0,1);
num1 = a;
num2 = b;
System.out.println("here is son's fun1");
}
@Override
void fun2(){
System.out.println("here is son's fun2");
}
}
先直接实践下,看输出结果:
疑问1:结果是调用了子类的fun2,为什么是子类呢?
这里我找到的解释是,子类在通过super调用到父类方法时,若方法中还调用了方法,则优先选择子类重写的方法,如果使用变量则选择父类变量。 深入点的解释就是,通过super调用到父类方法后,其实栈帧还是在子类对象中,所以在父类方法中调用到其他方法时,查寻方法表的时候,查的还是子类的方法表。(感觉这里解释的还不是很清楚,应该是我还没理解到虚拟机的内部实现原理,暂时先用这个作为初步的理解吧)
疑问2:这里没有调用父类构造方法,为什么还会有父类构造方法的输出呢?
Java中规定,实例化子类对象的时候,必须调用父类的构造方法,再调用子类的构造方法,所以其实在子类的构造方法的第一行是有一个隐式的调用super()的, 我理解的应该是子类要想继承父类的方法和属性,所以必须先有一个父类,所以必须先初始化父类?具体还是有点疑问,暂时存疑吧。