Java super用法详解
在继承关系中,子类会自动继承父类中定义的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写。
需要注意的是,在子类中重写的方法需要和父类中被重写的方法具有相同的方法名、参数列表及返回值类型。
【实例】重写继承的方法。
关键字 super 可用于访问父类中的构造方法、属性和方法。下面介绍关键字 super 的具体用法:
下面通过一个实例来介绍使用关键字 super 访问父类的属性和方法。
由运行结果可知,子类通过关键字 super 可以成功地访问父类的成员变量和成员方法。
实际上,当父类中有无参构造方法时,编译器默认在子类的所有构造方法中的第一行自动添加 super() 方法,隐式调用父类的无参构造方法。
【实例】隐式调用父类的构造方法。
构造方法的规则包括以下几点:
需要注意的是,在子类中重写的方法需要和父类中被重写的方法具有相同的方法名、参数列表及返回值类型。
【实例】重写继承的方法。
class Human { // 定义人类吃东西的方法 void eat() { System.out.println("人类吃东西"); } } // 定义 Sportsman 类继承 Human 类 class Sportsman extends Human { // 重写 eat() 方法 void eat() { System.out.println("运动员吃健身餐"); } } // 定义测试类 public class Test { public static void main(String[] args) { // 创建一个 Sportsman 实例对象 Sportsman s = new Sportsman(); // 调用 s 对象重写的 eat() 方法 s.eat(); } }运行结果为:
运动员吃健身餐
由实例的运行结果可知,当子类重写父类的方法后,子类对象将无法访问父类被重写的方法。如果在子类中访问父类的被隐藏的属性和重写的方法,那么需要使用关键字 super。关键字 super 可用于访问父类中的构造方法、属性和方法。下面介绍关键字 super 的具体用法:
//访问父类的构造方法 super(参数列表) //访问父类的属性 super.属性 //访问父类的方法 super.方法名()下面通过一个实例来介绍 super() 方法的应用。
/** * 定义父类 Human2 */ class Human2 { // 使用构造方法初始化属性 meal public String meal; Human2(String meal) { this.meal = meal; System.out.println("人类吃" + meal); } } /** * 定义子类 Sportsman2 */ class Sportsman2 extends Human2 { // 子类的构造方法通过关键字 super 调用父类的构造方法,并传递参数 // 此处必须调用,否则编译报错 Sportsman2(String meal) { super(meal); System.out.println("运动员吃东西"); } } public class Test { public static void main(String[] args) { // 子类实例化,调用父类和子类的构造方法 Sportsman2 b = new Sportsman2("早餐"); } }运行结果为:
人类吃早餐
运动员吃东西
下面通过一个实例来介绍使用关键字 super 访问父类的属性和方法。
class Human3 { String name = "人类"; // 定义人类吃东西的方法 void eat() { System.out.println("人类吃东西"); } } // 定义 Sportsman3 类继承 Human3 类 class Sportsman3 extends Human3 { String name = "一个人"; // 子类可以有自己的属性,这里覆盖了父类的属性 // 重写 eat() 方法 void eat() { // 访问父类的成员方法 super.eat(); // 这里可以添加运动员特有的吃东西行为 } // 定义打印 name 的方法 void printName() { // 访问父类的成员变量 System.out.println("name = " + super.name); } } public class Test { public static void main(String[] args) { // 创建一个 Sportsman3 实例对象 Sportsman3 x = new Sportsman3(); // 调用 x 对象重写的 eat() 方法 x.eat(); // 调用 x 对象的 printName() 方法 x.printName(); } }运行结果为:
人类吃东西
name = 人类
由运行结果可知,子类通过关键字 super 可以成功地访问父类的成员变量和成员方法。
实际上,当父类中有无参构造方法时,编译器默认在子类的所有构造方法中的第一行自动添加 super() 方法,隐式调用父类的无参构造方法。
【实例】隐式调用父类的构造方法。
/** * 定义父类 Human4 */ class Human4 { public int a; // 定义无参构造方法 Human4() { System.out.println("人类吃东西"); } // 构造方法,初始化 a Human4(int eat) { this.a = eat; } } /** * 定义 Sportsman4 类 */ class Sportsman4 extends Human4 { // 可以不写父类的构造方法的调用,默认隐式调用父类的无参构造方法 Sportsman4() { System.out.println("运动员吃东西"); } } public class Test { public static void main(String[] args) { // 创建 Sportsman4 的实例 Sportsman4 b = new Sportsman4(); } }运行结果为:
人类吃东西
运动员吃东西
class Sportsman4 extends Human4 { Sportsman4() { super(); // 隐含了这行代码 System.out.println("运动员吃东西"); } }假如 Sportsman4 类的构造方法没有参数,并且只调用 Human4 类的无参构造方法,正如上面例子所示,那么子类的构造方法也可以省略不写,如下所示:
class Sportsman4 extends Human4 { }如果执行上面的代码,实际上就是编译器默认添加了 Sportsman4 类的无参构造方法,并且在其中调用了 Human4 类的无参构造方法。但是,如果父类没有无参构造方法,那么在子类中必须使用关键字 super 显式调用父类的有参构造方法。这种隐式调用的方式使用得比较多,为了方便继承,在设计父类时都会提供一个无参构造方法。
构造方法的规则包括以下几点:
- 如果一个类中没有声明任何构造方法,那么编译器默认为该类添加一个无参的、空方法体的构造方法;
- 如果一个类中已声明有参构造方法,那么编译器不再默认添加无参构造方法;
- 如果一个构造方法的第一行没有显式声明语句 this(); 或 super();,那么编译器会自动添加 super(); 语句,隐式调用父类的无参构造方法。