继承进一步使用,以及super关键字
目标:
1)掌握子类对象实例化过程
2)掌握方法覆盖概念和实现。
3)掌握super关键字的作用。
一,子类对象实例化过程
子类对象在实例化之前,必须先调用父类中的构造方法,再调用子类中的构造方法。
class Person{ // 定义Person类 private String name ; // 定义name属性 private int age ; // 定义age属性 public Person(){ System.out.println("父类Person中的构造。") ; } public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age ; } public String getName(){ return this.name ; } public int getAge(){ return this.age ; } }; class Student extends Person{ // 定义Student类 private String school ; // 定义school属性 public Student(){ super() ; // 默认隐藏 System.out.println("子类Student中的构造。") ; } public void setSchool(String school){ this.school = school ; } public String getSchool(){ return this.school ; } }; public class InstanceDemo{ public static void main(String arsg[]){ Student stu = new Student() ;// 实例化子类对象 stu.setName("张三") ; // 此方法在Student类中没有明确定义 stu.setAge(30) ; stu.setSchool("清华大学") ; System.out.println("姓名:" + stu.getName() + ",年龄:" + stu.getAge() + ",学校:" + stu.getSchool() ) ; } };
运行结果:
父类Person中的构造。
子类Student中的构造。
姓名:张三,年龄:30,学校:清华大学
在生活中也很好理解,没有父亲就没有孩子。
实际上,对于子类的构造方法中,隐含了一个“super()”的语句。有时候,也将父类称为超类,所以调用父类构造方法,用super()。
super关键字必须写在构造方法的首行。
二,方法的复写
方法覆写就是指:子类中定义了与父类中同名的方法。
1)但是在方法覆写时必须考虑访问权限,即:被子类覆写的方法,不能拥有比父类更严格的访问权限。
2)所以,如果在父类中使用public定义的方法,子类的访问权限必须是public,否则无法编译。
3)private<default<public。
class Person{ // 定义父类 void print(){ // 默认的访问权限 System.out.println("Person --> void print()。") ; } }; class Student extends Person{ // 定义继承关系 public void print(){ System.out.println("Student --> void print()。") ; } }; public class OverrideDemo01{ public static void main(String args[]){ Student s = new Student() ; s.print() ; } };
运行结果:
Student-->void print()。
访问权限:
private:最小的访问权限。
default:什么都不写,例如:string name;
public:最大的访问权限。
以下是访问权限出问题的错误操作。
package methoud; class Person{ // 定义父类 public void print(){ // public的访问权限 System.out.println("Person --> void print()。") ; } }; class Student extends Person{ // 定义继承关系 void print(){ // 错误的,降低了访问权限 System.out.println("Student --> void print()。") ; } }; public class ThisDemo06{ public static void main(String args[]){ Student s = new Student() ; s.print() ; } };
由于子类的访问权限default小于public,所以编译通过不了。
从之前正确操作可以看出,如果子类将父类的方法覆写了,调用的时候,肯定是调用被覆写过的方法,那么如果非要调用父类的方法。
通过“super”关键字可以完成功能,super关键字可以从子类访问父类的内容。
如果要访问被覆写过的方法的方法:super.方法();
例如:
class Person{ // 定义父类 void print(){ // 默认的访问权限 System.out.println("Person --> void print()。") ; } }; class Student extends Person{ // 定义继承关系 public void print(){ super.print() ; // 访问父类中被子类覆写过的方法 System.out.println("Student --> void print()。") ; } }; public class OverrideDemo03{ public static void main(String args[]){ Student s = new Student() ; s.print() ; } };
运行结果:
Person --> void print()。
Student --> void print()。
如果要使用“super”不一定非要在方法覆写之后使用,也可以明确表示某个方法是从父类中继承而来的。
使用super只是更加明确的说直接从父类中寻找,就不从子类找了。因为没有super调用方法,首先从子类寻找,如果子类没有才到父类寻找。
例如:如果上面那个例子中super.print()把super去掉,就会造成无限期循环递归,自己调用自己。
三,问题:
如果父类中使用private关键字声明一个方法,那么在子类中使用default权限算是扩大权限,覆写吗?
答案是:NO,不算覆写。
正常覆写:
class Person{ // 定义父类 void print(){ // 默认的访问权限 System.out.println("Person --> void print()。") ; } public void fun(){ // 定义一个fun方法 this.print() ; // 调用print()方法 } }; class Student extends Person{ // 定义继承关系 void print(){ // 覆写父类中的方法 System.out.println("Student --> void print()。") ; } }; public class OverrideDemo04{ public static void main(String args[]){ Student s = new Student() ; s.fun() ; } };
运行结果:
Student --> void print()。
这里因为正常覆写,所以直接调用了子类中的覆写方法。
错误的覆写:
package methoud; class Person{ // 定义父类 private void print(){ // private的访问权限 System.out.println("Person --> void print()。") ; } public void fun(){ // 定义一个fun方法 this.print() ; // 调用print()方法 } }; class Student extends Person{ // 定义继承关系 void print(){ // 覆写父类中的方法 System.out.println("Student --> void print()。") ; } }; public class ThisDemo06{ public static void main(String args[]){ Student s = new Student() ; s.fun() ; } };
运行结果:
Person-->void print();
可见,这里并没有调用子类中的“覆写”方法,而是调用父类中默认的方法。说明这里并没有达到覆写的作用,子类中的方法其实是另外定义了一个方法。
这点需要注意!。
四,属性的覆盖。
覆盖,就是指子类中声明了父类中同名的属性。
class Person{ // 定义父类 public String info = "MLDN" ; // 定义一个公共属性 }; class Student extends Person{ // 定义继承关系 public String info = "LXH" ; // 定义了一个与父类中属性名称一致的属性 void print(){ // 覆写父类中的方法 System.out.println("父类中的属性:" + super.info) ; System.out.println("子类中的属性:" + this.info) ; } }; public class OverrideDemo05{ public static void main(String args[]){ Student s = new Student() ; s.print() ; } };
可见,要使用被覆盖的父类中的属性,需要使用super关键字。
五,方法覆盖与重载的区别
六,super关键字
super表示的是从子类调用父类中的指定操作。例如调用属性,方法,构造等等。
因为在子类实例化的时候,会默认调用父类中的无参数构造方法(“super()”)。如果想调用有参构造方法,则必须在子类中明确声明。
class Person{ // 定义Person类 private String name ; // 定义name属性 private int age ; // 定义age属性 public Person(String name,int age){ this.setName(name) ; this.setAge(age) ; } public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age ; } public String getName(){ return this.name ; } public int getAge(){ return this.age ; } public String getInfo(){ return "姓名:" + this.getName() + ";年龄:" + this.getAge() ; } }; class Student extends Person{ // 定义Student类 private String school ; // 定义school属性 public Student(String name,int age,String school){ super(name,age) ; // 明确调用父类中有两个参数的构造 this.school = school ; } public void setSchool(String school){ this.school = school ; } public String getSchool(){ return this.school ; } public String getInfo(){ return super.getInfo() + ";学校:" + this.getSchool() ; } }; public class SuperDemo01{ public static void main(String arsg[]){ Student stu = new Student("张三",30,"清华大学") ;// 实例化子类对象 System.out.println(stu.getInfo()) ; } };
不管任何时候,子类实例化的时候,永远要先去调用父类中的构造方法,默认调用的是无参构造方法。
1)对于this和super本身都可以调用构造方法,而且调用的时候都必须放在构造方法的首行。所以这两个方法肯定不能同时出现。