了解了继承的基本概念后,下面对继承操作中的一些注意点进行研究。
一. 子类对象的实例化过程
在继承的操作中,对于子类对象实例化也是有要求的,及子类对象在实例化之前必须首先调用父类中的构造方法后在调用自己的构造方法。
【子类的实例化过程】
class Person
{
private String name;
private int age;
public Person(){
System.out.println("这是父类中的构造方法");
}
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
}
class Student extends Person
{
private String school;
public Student(){
System.out.println("这是子类中的构造方法");
}
public void setSchool(String school){
this.school=school;
}
public String getSchool(){
return school;
}
}
public class ExtDemo2
{
public static void main(String args[]){
Student stu=new Student();
stu.setName("张三");
stu.setAge(19);
stu.setSchool("ZZU");
System.out.println("姓名:"+stu.getName()+",年龄:"+stu.getAge()+",学校:"+stu.getSchool());
}
}
运行结果为:
从运行结果可以清楚的发现,子类对象在实例化前会默认调用父类中的构造方法。就好像没有父类就没有孩子。
当然对于以上代码实际上在子类的构造方法中隐含了一个super()的语法,代码如下:
class Student extends Person
{
private String school;
public Student(){
super();
System.out.println("这是子类中的构造方法");
}
public void setSchool(String school){
this.school=school;
}
public String getSchool(){
return school;
}
}
以上程序的运行结果与之前是一样的。super表示超级的意思,在一些书中也喜欢把父类叫做超类,上面的语法就是表示子类可以直接使用super()调用父类(超类)中的无参构造。
二. 方法的覆写
在继承的关系中也存在着方法覆写的概念,所谓的方法覆写就是子类定义了与父类中名称相同的方法,但是在覆写时必须考虑到权限,即被子类覆写的方法不能拥有比父类方法更严格的访问权限。
【方法的覆写】
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[]){
new Student().print();
}
}
运行结果为:
从程序的运行结果可以发现,Student子类定义了与Person父类中同名的方法,但是在子类中此方法的访问权限被扩大了,符合覆写的概念,当方法被覆写后,子类对象调用的就是被覆写后的方法。
需要注意的是,在被子类覆写的方法权限缩小时,会在编译时产生错误。
实际上与方法的覆写概念相同的还有另外一种称为属性的覆盖,这点在开发中使用较少。
【属性的覆盖】
class Person
{
public String info="ZZU";
}
class Student extends Person
{
public String info="zhao";
public void print(){
System.out.println("父类中的属性:"+super.info);
System.out.println("子类中的属性:"+this.info);
}
}
public class OverrideDemo05
{
public static void main(String args[]){
new Student().print();
}
}
运行结果为:
以上程序只作为参考使用,读者只需要了解到,如果父类和子类声明了同样名称的属性,则在子类中直接访问时一定是采用“就近原则”,即先找到本类中的属性,如果此时要调用父类中的属性,直接使用super.属性 格式进行调用。
可以发现方法的重载和覆写十分相似,下面进行对比:
*重载:(Overloading)定义:方法名称相同,参数的个数和类型不同,对权限没有要求。发生在一个类中。
覆写:(Overriding)定义:方法名称相同,参数的类型、返回值类型完全相同,被覆写的方法不能拥有更严格的权限,发生在继承类中。*
三. super关键字的作用
在上面的程序中一直有super关键字,使用super关键字可以从子类中调用父类中的构造方法、普通方法和属性。之前演示了调用普通方法和属性的的基本操作,下面使用super调用父类中指定的构造方法,与this调用构造方法的要求相同,语句必须放在子类构造方法的首行。
【使用super调用父类中指定的构造方法】
class Person
{
private String name;
private int age;
public Person(){
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()) ;
}
};
运行结果:
姓名:张三;年龄:30;学校:清华大学
在以上程序中使用了super()的形式调用了父类中的构造方法,在子类中又覆写了父类中的getInfo()方法,所以输出的内容是子类中定义的内容。可以发现super和this关键字有相似之处,那么对比如下:
***super:访问父类中的属性,直接访问父类中的方法,调用父类构造,必须放在子类构造方法的首行。
this:访问本类中的属性,如果在本类中没有此属性,则从父类中继续查找,访问本类中的方法,如果没有则在父类中继续进行查找,调用本类构造方法,必须放在构造方法的首行,可以表示当前对象。*
既然this和super都可以调用构造方法,但是this和super不能同时出现,因为在两者调用构造方法时都必须在构造方法的首行,另外注意,无论子类如何操作,最终必须首先调用父类中的构造方法。