虽然只是一个关键字,但是我认为super关键字是Java学习中的一个小难点。因为这个关键字涉及了Java中父类和子类的继承机制的实现。
super关键字的作用
super关键字的作用是调用子类所复制的父类的字段或者方法(也包括构造方法)。
在这里,子类在继承父类的时候会复制父类的字段和方法。在创建子类对象时,在堆内存中,除了子类的对象外,也会同时建立一个父类的对象,这两者是创建对象时同时创建的,这就是子类对象的创建机制。此时,this关键字代表子类对象的引用,super关键字代表子类对象中包含的父类对象的引用。
调用的格式是:
super.子类所复制的父类的字段
super.子类所复制的父类中的方法();
super(参数列表); //子类所复制的构造方法,参数列表可以为空
下面的例子说明了如何在子类中使用super关键字调用(子类所复制的)父类字段和方法
class Person{ //父类
String name; //父类的字段 name
int age; //父类的字段 age
public String talk(){ //父类的方法talk()
return "I am:"+this.name+" I am "+this.age; //返回此父类的name和age的值
}
}
class Student extends Person{ //子类
String school; //子类的独有字段school
public Student(){ //重载子类的构造方法
System.out.println(super.name); //构造子类对象时,输出子类所复制的父类的name和age的值
System.out.println(super.age);
}
public void init(String name,int age,String School){ //子类的init方法,用来初始化子类所复制的父类的name和age的值
super.name = name;
super.age = age;
System.out.print(super.talk()); //子类中使用super关键字调用父类的talk方法
this.school = School; //将方法传入的参数值赋值给子类的school字段
}
}
public class test2{ //测试类
public static void main(String[] args){ //主方法
Student s = new Student(); //创建子类的对象,即调用子类的构造方法
System.out.println(s.name); //输出子类的name默认值,null
System.out.println(s.age); //输出子类的age的默认值,0
s.init("Jim",25,"abcde"); //调用子类的init方法,此方法将传入的参数赋值给(子类所复制的)父类对象,从而改变父类对象的字段值
System.out.println(",school:"+s.school); //输出子类的字段school的值,“abcde”
System.out.println(s.name); //输出子类此时的字段name的值,Jim
System.out.println(s.age); //输出子类此时的字段age的值,25
}
}
我这里发现一个小问题,就是通过改变子类所复制的父类的字段的值,可以联动地改变子类的相应字段的值。通过改变子类的相应字段的值,也可以联动地改变父类相应字段的值。所以,我严重怀疑这两部分内容在内存中是重合的。暂且存疑吧。
同样,也可以使用super关键字调用子类所复制的父类的构造方法。例如:
class Person{ //父类
String name; //父类的字段name
int age; //父类的字段age
public Person(String name, int age){ //父类的构造方法,构造方法接收参数并赋值
this.name = name;
this.age = age;
}
}
class Student extends Person{ //子类
String school; //子类的字段school
public Student(){ //子类重载的构造方法
super("Tom",25); //使用super关键字调用父类的构造方法并传递参数
} //当子父类的构造方法带有参数时,子类调用父类构造方法时也必须相应给出参数,否则会出错。
}
public class test3{
public static void main(String[] args){
Student s = new Student(); //创建子类对象
s.school = "abcde"; //给子类字段school赋值
System.out.println(s.name); //输出子类字段name的值
System.out.println(s.age); //输出子类字段age的值
System.out.println(s.school); //输出子类字段school的值
}
}