继承(extends)
- 继承可以定义一个通用的类(即父类),之后扩展该类为一个更加特定的类(即子类)。
- 使用类来对同一类型的对象建模。不同的类也可能会有一些共同的特征和行为,这些共同的特征和行为都统一放在一个类中,可以被其他类所共享。可以自定义特定的类继承自通用类(父类),这些特定的类继承通用类中的特征和方法。
- 在Java术语中,如果类c2扩展自另有一个类c1,那么就将c2称作子类(次类,扩展类,派生类),将c1称作父类(超类,基类)。子类从它的父类中继承可访问的数据域和方法,还可以添加新的数据域和方法。
- 父类中的私有数据域在该类之外是不可访问的,所以不能在子类中直接使用。但是在父类中定义了公共的访问器/修改器,那么就可以通过这些公共的访问器/修改器来访问和修改这些私有类。
- 继承是用来为“是一种”(is-a)关系建模的。一个父类和子类之间必须存在“是一种”(is-a)关系。不要仅仅是为了重用方法而去随便地扩展一个类,比如一个Person类和Tree类,尽管存在类似高度和重量这样的通用属性,但是从Person类中扩展出Tree类并没有意义。
- 在Java中一个Java类只可能是直接继承自一个子类,这种限制成为单一继承。如果使用extends关键字来定义一个子类,只允许有一个父类。想要多重继承是可以通过接口来实现的。
定义一个动物父类:
public class Animal {
private String name;
private String color;
public Animal() {
}
public Animal(String name, String color) {
this.name = name;
this.color = color;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setColor(String color) {
this.color = color;
}
public String getColor() {
return color;
}
}
定义一个猫类来继承动物类:
public class Cat extends Animal {
private String meow;
private String size;
public Cat() {
}
public Cat(String yail, String size) {
this.meow = yail;
this.size = size;
}
public Cat(String name, String color, String yail, String size) {
super(name, color); //通过super关键字调用父类的构造方法
setName(name);
setColor(color); //调用父类的set方法进行修改
this.meow = yail;
this.size = size;
}
public void setMeow(String Meow) {
this.meow = Meow;
}
public String getMeow() {
return meow;
}
public void setSize(String size) {
this.size = size;
}
public String getSize() {
return size;
}
public void action(){
System.out.println("The " + getName()+ " can " + meow + ". It's color is " + getColor() + ". It's " + size) ;
}
}
定义一个测试类:
public class catTest {
public static void main(String[] args) {
Cat cat = new Cat();
// cat调用父类的set方法进行修改name属性
cat.setName("cat");
cat.setColor("white");
cat.setMeow("miao miao");
cat.setSize("small");
cat.action();
}
}
控制台输出结果为:
构造方法链
-
子类的构造方法可以调用重载的构造方法或者父类的构造方法。如果子类中没有显式的调用父类的构造方法,编译器就会自动把super() 作为构造方法的第一条语句。例如:
-
在构造一个类的实例时,将会调用沿着继承链的所有父类的构造方法。构造一个子类的对象时,子类构造方法会在完成自己的任务之前,首先调用它的父类的构造方法。如果此时父类继承自其他类时,那么父类在完成自己的任务之前,调用它自己的父类的构造方法。这个过程会持续到沿着这个继承体系结构的最后一个构造方法被调用为止。以上就是构造方法链。
例如:定义一个Person类
class Person {
public Person() {
System.out.println("(1) Perform Person's tasks");
}
}
定义一个Employee类继承Person类:
class Employee extends Person {
public Employee() {
//此时编译器自动添加了super();
//this调用其他构造方法,放在第一个语句
this("(2) Invoke Employee's overload constructor");
System.out.println("(3) Perform Employee's tasks");
}
public Employee(String s){
System.out.println(s);
}
}
定义一个Faulty类继承Employee类:
public class Faculty extends Employee{
public static void main(String[] args) {
new Faculty(); //调用无参构造方法
}
public Faculty() {
System.out.println("(4) Perform Faculty's tasks");
}
}
在控制台输出的结果是:
注意:要调用父类构造方法就必须使用关键字super,而且这个调用必须是构造方法的第一条语句,在子类中调用父类构造方法的名字会引起一个语法错误。
例如:
在类中只有无参构造时:
public class C {
public static void main(String[] args) {
new B(); //B中调用了A的无参构造
}
}
class A{
public A() {
System.out.println("print a" );
}
}
class B extends A{
// 直接调用了A的无参构造
}
控制台输出:
当A类中没有无参构造时:
调用A中的有参构造,此时关键字super就必不可少了:
控制台输出结果:
- 关键字super不仅可以引用父类的构造方法,也可以引用父类的方法。使用语法:super.(参数);