java extends - yaokun123/php-wiki GitHub Wiki

继承

一、继承的概述

继承的好处

1、提高了代码的复用性
2、让类与类之间产生了关系,给第三个特征多态提供了前提。

多重继承问题

java中支持单继承,不直接支持多继承,但对C++中多继承机制进行了改良。

单继承:一个子类只能有一个直接父类。
多继承:一个子类可以有多个直接父类(java中不允许,进行改良-》多重继承)
      不直接支持是因为多个父类中有相同的成员时,会产生调用不确定性。

二、继承的特点

在子父类中,成员的特点体现

  • 成员变量
当本类的成员变量和局部变量同名时,用this区分
当子父类中的成员变量同名时,用super区分父类

this代表一个本类对象的引用
super代表一个父类空间
  • 成员函数
当子父类中出现成员函数一模一样(函数名、返回值、参数个数、参数类型)的情况,会运行子类的函数。这种现象,称为覆盖操作。

函数两个特性:
1、重载。同一个类中
2、覆盖。子类中。覆盖也称为重写,覆写。

注意:

子类方法覆盖父类方法时,子类全县必须要大于等于父类的权限。

静态只能覆盖静态,或被静态覆盖。

  • 构造函数
子父类的构造函数特点:

在子类构造对象时候,发现,访问子类构造函数时,父类也就运行了。
原因是:在子类构造函数中第一行有一个默认的隐式语句。super()

注意:

子类的实例化过程:子类中所有的构造函数默认都会访问父类中的空参数的构造函数。 super语句必须要定义在子类构造函数的第一行。因为父类的初始化动作要先完成。

为什么子类实例化的时候要访问父类中的构造函数呢?

那是因为子类继承了父类,获取到了父类中内容(属性),所以在使用父类内容之前 要先看父类是如何对自己初始化的。

所以子类在构造对象时,必须访问父类中的构造函数, 为了完成这个必须的动作,就在子类中的构造函数中加了super()语句。

如果父类中没有定义空参数构造函数,那么子类的构造函数必须用super明确要调用父类中哪个构造函数。

父类中哪个构造函数,同时再累构造函数中如果使用this调用了本类构造函数时,那么super就没有了。 因为super和this都只能定义第一行,所以只能有一个。但是可以保证的是,子类中肯定会有其他的构造函数 访问父类的构造函数。

示例代码

class Fu{
    Fu(){
        System.out.println("Fu run");
    }
}

class Zi{
    Zi(){
        //这里有一个隐式语句,调用的就是父类中的空参数的构造函数。
        //如果父类中没有空参数的构造函数,则会报错。
        //super()
        System.out.println("Zi run");
    }
}

class ExtendsDemo{
    public function void main(){
        new Zi();
    }
}

子父类中的成员变量内存图解

子父类中的构造函数-子类的实例化过程图解

class Fu{
    Fu(){
        super();
        show();
        return;
    }
    void show(){
        System.out.println("fu show");
    }
}

class Zi extends Fu{
    int num = 8;
    Zi(){
        super();
        //-->通过super初始化父类内容时,子类的成员变量并未显示初始化。等super()父类初始化完毕后
        //才进行子类成员变量的显示初始化。
        System.out.println("zi cons run...."+num);
        return;
    }

    void show(){
 
        System.out.println("zi show..."+num);
    }
}

class ExtendsDemo{
    public static void main(String[] args){
        
    }
}

一个对象实例化过程

Person p = new Person();

1、JVM会读取指定路径下的Person.class文件,并加载进内存,并会先加载Person的父类
(如果有直接的父类情况下)

2、在堆内存中的开辟空间,分配地址

3、在对象空间中,对对象属性进行默认初始化。

4、调用对应的构造函数进行初始化。

5、在构造函数中,第一行会先调用父类中的构造函数进行初始化。

6、父类初始化完毕后,再对子类的属性进行显示初始化。

7、再进行子类构造函数的特定初始化

8、初始化完毕后,将地址赋值给引用变量。

三、final关键字

final可以修饰类、方法、变量

final修饰的类不可以被继承

final修饰的方法不可以被覆盖

final修饰的变量是一个常量,只能被赋值一次

内部类只能访问被final修饰的局部变量。

四、抽象类

抽象类特点

1、方法只有声明没有实现,该方法就是抽象方法,需要被abstract修饰。

2、抽象方法必须定义在抽象类中,该类必须也被abstract修饰

3、抽象类不可以被实例化。只能被继承。

4、继承抽象类的子类,必须覆盖抽象类的所有抽象方法后,该子类才可以实例化。否则该子类还是抽象类。

问答

1、抽象类中有构造函数吗?
有,用于给子类对象进行初始化

2、抽象类可以不定义抽象方法吗?
可以的,但是很少见,目的就是不让该类创建对象。AWT的适配器对象就是这种类

3、抽象关键字不可以和哪些关键字共存?
private/static/final

4、抽象类和一般类的区别?
一般类中不能定义抽象方法,抽象类中可以定义抽象方法。
一般类可以被实例化,抽象类不能被实例化。

5、抽象类一定是个父类吗?
是的。因为需要子类覆盖其方法后才可以对子类实例化。

五、接口

当一个抽象类中的方法都是抽象方法的时候,这时可以将该抽象类用另一种形式定义和表示,就是接口-interface

格式:定义接口使用的的关键字不是class而是interface
interface{}

接口中的成员修饰符是固定的
成员常量:public static final
成员函数:public abstract
发现接口中的成员都是public的

接口的出现将“多继承”通过另一种形式体现出来,即“多实现”

接口的实现————implements

类与类之间是继承关系,类与接口之间是实现关系

接口是一个特殊的抽象类,任然不可以被实例化,只能由实现了接口的子类覆盖了接口中所有的抽象方法后,该子类、才可以实例化。否则这个子类就是一个抽象类

在java中不直接支持多继承,因为会出现调用的不确定性,所以java将多继承机制进行改良,在java中变成多实现。一个类可以实现多个接口

一个类在继承另一个类的同时,还可以实现多个接口

接口的特点

1、接口是对外暴露的规则

2、接口是程序的功能扩展

3、接口的出现降低耦合性

4、接口可以用来多实现

接口与抽象类的区别

共性:都是不断抽取出来的抽象概念

区别1:抽象类体现继承关系,一个类只能但继承
     接口体现实现关系,一个类可以多实现

区别2:抽象类是继承,是"is a"关系
      接口是实现,是"like a"关系

区别3:抽象类可以定义非抽象方法,供子类直接使用
      接口中的方法都是抽象的,接口中的成员都有固定修饰符。