继承的引出
首先编写两个类:Animals类和Tiger类
Animals类:
public class Animals {
private String breed;//品种
private int age;
public String getBreed() {
return breed;
}
public void setBreed(String breed) {
this.breed = breed;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Tiger类:
public class Tiger {
private String breed;//品种
private int age;//年龄
public String getBreed() {
return breed;
}
public void setBreed(String breed) {
this.breed = breed;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
从上述的两个类中我们可以发现,他们的属性是完全相同的,这样就使得代码发现了重复,过于冗余,所以我们在想,能不能找到一种方法,能够只写一遍代码,两个类都能够进行使用,由此,就引出了继承的概念
继承的概念
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
由此我们可以看出
继承的作用:能够快速创建新类,实现代码的复用、减少冗余,有利于对程序做模块化切割,提高程序的可维护性,大大提高开发效率和开发质量。
那么子类应该如何如何继承父类呢?
在Java之中,如果要实现继承的关系,可以使用下面这种语法:
class 父类{
... //成员变量、成员方法
}
class 子类 extends 父类{
... //类体
}
子类又称派生类(derived class),父类又称基类(base class),也称超类(super class)。
那么我们对上面代码进行修改
public class Animals {
private String breed;//品种
private int age;
public String getBreed() {
return breed;
}
public void setBreed(String breed) {
this.breed = breed;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class Tiger extends Animals {
}
public static void main(String[] args) {
Tiger tiger = new Tiger();//实例化子类
tiger.setBreed("小白虎");//Animals中的定义
tiger.setAge(18);//Animals中的定义
System.out.println("品种:"+tiger.getBreed()+",年龄:"+tiger.getAge());
}
}
输出结果
品种:小白虎,年龄:18
这个Animal类就可以作为一个父类,然后Tiger类,继承这个类之后,就具有了父类当中的属性和方法,子类就不会存在重复的代码,这就体现了出了继承的作用。
继承的限制
Java 不支持多继承,但支持多重继承
限制一:一个子类只能继承有一个父类。
错误写法:
class A {}
class B {}
class C extends A,B {} // 一个子类继承了两个父类
正确写法:
class A {}
class B extends A {}
class C extends B {}
我们可以用一张图更清晰的看出来继承之间的关系
C实际上是属于子(孙)类,但是由于B类继承了A类的全部方法,而C类又继承了B类的全部方法,由此可以看出C类同时继承了A类和B类的方法,这种操作称为多层继承。
Object类是所有Java类的父类,其属性和方法为所有Java类所共有。
结论:Java之中允许存在多层继承,但是不允许存在多重继承,Java存在单继承局限。
限制二:在一个继承关系中,子类构造自身时,必须也要一并构造自己体内的父类部分,然后再进行调用子类构造。
例如:
public class A {
/**父类无参构造方法*/
public A() {
System.out.println("我是A类");
}
}
public class B extends A {
public B() {
/**子类无参构造方法*/
System.out.println("我是B类");
}
}
public class Tester2 {
public static void main(String[] args) {
B b = new B();//实例化子类
}
}
输出结果
我是A类
我是B类
这个时候虽然调用的是B类,但是它将A类中的无参构造方法一并输出,说明它会默认先执行父类构造,先调用父类构造的方法体执行,然后再实例化子类对象,调用子类的构造方法。此时,代码中包含着一个省略的super()方法。
完整代码应为:
public class B extends A {
public B() {
super();
/**子类无参构造方法*/
System.out.println("我是B类");
}
}
我们可以来说说Java中的两个关键字
super关键字: 一是调用超类的方法,二是调用父类的其他构造器
this关键字: 一是指示隐式参数的引用,而是调用该类的其他构造器
在调用父类构造方法时,父类构造方法的调用必须是子类构造方法的第一条语句,例如上面的例子,super()方法必须为首行,否则编译器会进行报错。
注意点:
1.子类构造自身时,同时也要一并构造自己体内的父类部分
2.子类不能对自身体内的父类部分进行初始化,而必须调用父类构造方法来完成自己体内父类部分的构造
3.子类构造自身时,需要先调用父类构造方法,完成自己体内的父类部分的初始化,然后才能初始化自身特有的部分。
4.一个Java类如果没有明确在其构造方法中调用父类的哪个构造方法,默认就是调用super();
5.父类引用变量可以指向所有的子类对象,但是在父类引用变量中,其只看到子类对象的父类部分,调用能力有限。这叫做“萎缩”效应,有功能不用是可以的。
6.子类引用变量不能指向父类对象,因为在子类引用变量眼中其看到所有的对象都是子类对象,其会尝试把一个父类对象“膨胀”为一个子类对象,无中生有是不可以的。