本章目标
掌握子类对象的实例化过程
掌握方法覆写的概念及实现
掌握super关键字的作用
子类对象实例化过程
在继承的操作中,对于子类对象的实例化也是有要求的:“子类对象在实例化之前必须首先调用父类中的构造方法之后再调用子类自己的构造方法”。
观察子类对象的实例化过程
class Person{//定义 Person 类 private String name;//定义 name 属性 private int age;//定义 age 属性 public Person(){ System.out.println("父类 Person 中的构造。");//父类的构造方法 } public String getName() {//取得 name 属性 return name; } public void setName(String name) {//设置 name 属性 this.name = name; } public int getAge() {//取得 age 属性 return age; } public void setAge(int age) {//设置 age 属性 this.age = age; } } class Student extends Person{//Student 是 Person 的子类,扩展父类的功能 private String school;//新定义的属性 school public Student(){ super();//加与不加此语句效果相同 System.out.println("子类 Student 中的构造。");//子类的构造方法 } public String getSchool() {//取得 school 属性 return school; } public void setSchool(String school) {//设置 school 属性 this.school = school; } } public class InstanceDemo { public static void main(String[] args) { Student stu = new Student(); stu.setName("张三");//此时访问的方法是父类中的,子类中并没有定义 stu.setAge(30);//此时访问的方法是父类中的,子类中并没有定义 stu.setSchool("My school");//此时的方法是在子类中定义的 System.out.println("姓名:"+stu.getName()+"; 年龄:"+stu.getAge()+"; 学校:"+stu.getSchool()); } /* 结果: * 父类 Person 中的构造。 * 子类 Student 中的构造。 * 姓名:张三; 年龄:30; 学校:My school * */ }
隐含的语句
对于以上的代码实际在子类的构造方法中隐含了一个super()的语法
class Student extends Person { // Student是Person的子类,扩展父类的功能
private String school; // 新定义的属性school
public Student(){
super() ; // 加与不加此语句效果一致
System.out.println("子类Student中的构造。") ; // 子类的构造方法
}
public String getSchool() { // 取得school属性
return school;
}
public void setSchool(String school) { // 设置school属性
this.school = school;
}
方法的覆写
在继承的关系中也存在着方法覆写的概念,所谓的方法覆写就是指子类定义了与父类中同名的方法,但是在方法覆写时必须考虑到权限,即:被子类覆写的方法不能拥有比父类方法更加严格的访问权限。
已学习过的三种访问权限:
——关于访问权限,实际上前几章读者已经见过三种访问权限了:private、default、public,这三种访问权限的具体作用本书后面会有介绍,读者现在只需要记住大小关系即可:private < default < public。
所以,如果在父类中使用public定义的方法,子类的访问权限必须是public,否则程序会无法编译。
方法的覆写
class Person{ void print(){//定义一个默认访问权限的方法 System.out.println("Person --> void print(){}"); } } class Student extends Person{//定义一个子类继承 Person 类 public void print(){//覆写父类中的方法,扩大了权限 System.out.println("Student --> void print(){}"); } } public class OverrideDemo01 { public static void main(String[] args) { new Student().print();//此处执行的是被覆写的方法 } /* 结果: * Student --> void print(){} * */ }
错误的方法覆写
如果现在被子类覆写的方法权限缩小的话,则在编译时将出现错误提示。
class Person{
public void print(){ // 定义一个默认访问权限的方法
System.out.println("Person --> void print(){}") ;
}
}
class Student extends Person{ // 定义一个子类继承Person类
void print(){ // 覆写父类中的方法,但缩小了权限,错误
System.out.println("Student --> void print(){}") ;
}
}
调用父类中被子类覆写过的方法
class Person{ void print(){//定义一个默认访问权限的方法 System.out.println("Person --> void print(){}"); } } class Student extends Person{//定义一个子类继承 Person 类 public void print(){//覆写父类中的方法,扩大了权限 super.print();//调用父类中的 print()方法 System.out.println("Student --> void print(){}"); } } public class OverrideDemo03 { public static void main(String[] args) { new Student().print();//此处执行的是被覆写的方法 } /* 结果: * Person --> void print(){} * Student --> void print(){} * */ }
思考?
如果现在将父类的一个方法定义成private访问权限,在子类中将此方法声明为default访问权限,那么这样还叫做覆写吗?
class Person{ private void print(){//方法用 private 访问权限 System.out.println("Person --> void print(){}"); } public void fun(){//定义一个 fun 方法 this.print();//调用 print() } } class Student extends Person{//定义一个子类继承 Person 类 void print(){//覆写父类中的方法,扩大了权限 System.out.println("Student --> void print(){}"); } } public class OverrideDemo04 { public static void main(String[] args) { new Student().fun(); } /* 结果: * Person --> void print(){} * */ }
属性的覆盖
在继承中除了方法可以覆写之外,属性也可以覆盖,所谓的属性覆盖就是指子类声明了与父类同名的属性。
class Person{ public String info = "父类的属性";//定义一个公共属性 } class Student extends Person{//定义一个子类继承 Person 类 public String info = "子类的属性";//此属性与父类中的属性名称一致 public void print(){ System.out.println("父类中的属性:"+super.info);//访问父类中的 info 属性 System.out.println("子类中的属性:"+this.info);//访问本类中的 info 属性 } } public class OverrideDemo05 { public static void main(String[] args) { new Student().print();//访问 print() 方法 } /* 结果: * 父类中的属性:父类的属性 * 子类中的属性:子类的属性 * */ }
方法的重载与覆写的区别
super关键字的作用
使用super可以从子类中调用父类中的构造方法、普通方法、属性。
使用super调用父类中的指定构造方法
class Person{//定义父类 Person private String name;//定义 name 属性 private int age;//定义 age 属性 public Person(String name, int age) {//通过构造方法设置 name 和 age this.setName(name);//设置 name 属性内容 this.setAge(age);//设置 age 属性内容 } public String getName() {//取得 name 属性 return name; } public void setName(String name) {//设置 name 属性 this.name = name; } public int getAge() {//取得 age 属性 return age; } public void setAge(int age) {//设置 age 属性 this.age = age; } public String getInfo(){//信息输出 return "姓名:"+this.getName()+"; 年龄:"+this.getAge(); } } class Student extends Person{//Student 是 Person 的子类,扩展父类的功能 private String school;//新定义的属性 school public Student(String name, int age, String school){ super(name,age);//指定调用父类中的构造方法 this.setSchool(school); } public String getSchool() {//取得 school 属性 return school; } public void setSchool(String school) {//设置 school 属性 this.school = school; } public String getInfo(){//覆写父类中的方法 //扩充父类中的方法 return super.getInfo()+"; 学校:"+this.getSchool(); } } public class SuperDemo01 { public static void main(String[] args) { Student stu = new Student("张三", 30, "myShool"); //打印信息,调用覆写过的方法 System.out.println(stu.getInfo()); } /* 结果: * 姓名:张三; 年龄:30; 学校:myShool * */ }
this与super的区别