为什么要有继承,继承的作用?
继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。
作用:进行共性抽取,实现代码的复用
//代码一
public class Cat {
public String name;
public int age;
public void meow(){
System.out.println(this.name + "喵喵叫");
}
}
//代码二
public class Dog {
public String name;
public int age;
public void bark(){
System.out.println(this.name + "汪汪叫");
}
}
对上述代码一和代码二,我们不难发现他们有着共同字段 name 和 age,因此可以将两段代码的共性抽取出来,放到Animal类中,如下
public class Animal {
public String name;
public int age;
}
这样就将共性抽取了出来,如果以后还有别的动物需定义一个类,就可以继承Animal类,从而达到代码的复用。那么怎么写继承呢?请看下文。
语法
表示类之间的继承关系,用 extends 关键字。
修饰符 class 子类/派生类 extends 父类/基类/超类{
}
//例
public class Animal {
public String name;
public int age;
}
public class Cat extends Animal{//将Animal类字段name和age继承过来且有自己的成员
public void meow(){
System.out.println(this.name + "喵喵叫");
}
}
- 子类会将父类中的成员变量或成员方法继承到子类中
- 子类继承父类后,需添加自己特有的成员,体现出与父类不同,否则没必要继承
子类访问父类成员
- 子类访问父类成员变量
当父类和子类拥有同名的成员变量时,优先访问子类成员变量,若要在子类中访问与父类同名的成员变量,则需借助super关键字==(super.成员变量)==- 当父类和子类拥有同名成员方法时,优先访问子类成员方法,若要在子类中访问与父类同名的成员方法,则需借助super(super.成员方法)
子类构造方法
子类对象构造时 ,需先调用基类构造方法,来帮助基类成员方法初始化,然后执行子类构造方法。
public class Animal {
public String name;
public int age;
public Animal(String name,int age){
this.name = name;
this.age = age;
}
}
public class Dog extends Animal{
public Dog(String name,int age){
super(name,age);//用super(参数列表名)来调用父类构造方法,帮助父类成员进行初始化
System.out.println("==构造方法执行==");
}
public void bark(){
System.out.println(this.name + "汪汪叫");
}
}
public class Test {
public static void main(String[] args) {
Dog dog = new Dog("dog",2);
}
}
上述代码中,Dog类这个子类中调用了构造方法(子类构造方法),那么就需要先调用父类的构造方法(用super(参数列表)),也就是Animal类的构造方法来帮助Animal类的成员初始化,然后再继续执行子类构造方法,打印出构造方法执行。
注意:构造方法中 super(参数列表)或 this(方法名)都必须放在构造方法中的第一行,且不能在静态方法中使用
如果父类没有定义构造方法或者定义了无参的构造方法,那么子类构造方法第一行会有隐藏的super()调用(子类构造方法执行前会先调用父类的构造方法【用super()调用】,如果父类没有显示定义构造方法,则Java会提供默认的不带参数的构造方法)
代码块执行顺序
- 静态代码块先执行且只执行一次,在类加载阶段执行
- 当有对象创建时,执行实例代码块,后执行构造方法
当有父类和子类时,先执行父类和子类的静态代码块,再执行父类的实例代码块和构造方法,再执行子类的实例代码块和构造方法,且如果是第二次实例化子类对象时,父类和子类的静态代码块不会再执行(静态代码块只执行一次)
//父类
public class Father {
public String name;
public int age;
static {
System.out.println("父类静态代码块");
}
{
System.out.println("父类实例代码块");
}
public Father(String name,int age){
this.name = name;
this.age = age;
System.out.println("父类构造方法");
}
}
//子类
public class Son extends Father{
static {
System.out.println("子类静态代码块");
}
{
System.out.println("子类实例代码块");
}
public Son(String name,int age){
super(name,age);
System.out.println("子类构造方法");
}
}
//测试类
public class Test {
public static void main(String[] args) {
Son son = new Son("dog",3);
System.out.println("===========================");//分割线
Son son2 = new Son("cat",2);
}
}
有上述代码和运行结果可知上文所说的执行顺序以及静态代码块只执行一次