继承
继承是同样是一种抽象,在现实与编码工作中都普遍存在。在我的定义里,编码过程中,或者说是软件过程中的继承是类似一颗二叉树,一个结点可以有多个孩子,这叫继承,在继承的过程中,孩子继承了父类的特定数据成员与方法,除了父类私有数据成员和构造方法。
同样,因此一个孩子不能有多个父亲(Java中不支持),如果有,那就是使用接口完成。
extend
1 | class son extends father{ |
创建了一个类,son类继承father类的 j , n ,s。
interface
现在不懂,以后再写。
protected
主要是为了提供的给子类使用。子类可以通过继承获取protected 修饰的变量或者方法,但是如果子类的与父类不在同一个包内,子类只能使用public修饰的变量或者方法。
sup
sup关键字设置出来的目的便是为了子类显示调用父类的构造方法。根据不同的情况进行判定使用,例如以下方式:
- sup() 显示调用的父类的无参构造方法
- sup(int i) 显示调用父类的另外一个构造方法(构造方法可以重载,也可以有多个)
- sup.xxx() 调用父类的xxx方法
程序执行
注明一点,在目前已知的所有类中都有父类。除了Object类。
在一个子类中从开始执行程序,到程序结束,究竟是如何初始化的以及调用的。
先确定一点的便是,实例存储空间和初值–> 构造方法(所有实例变量进行初始化)
加载类,创建对象有很大区别。加载类在创建对象前。在加载时就会将所有静态变量一起加载了
可以看出,在类的载入和一个类中的初始化的顺序程序执行是息息相关的。所以根据我理解是这样的。
现在假设有三个类,子类,父类,和Object类。其中父类和子类都有自己的显示构造方法,无参构造方法,静态变量,实例变量。当程序开始执行,首先采取的是载入阶段。
载入阶段:
在类的载入阶段中,从子类A开始载入,发现A子类有一个父类B,且这个父类B还没有载入。现在立刻停止子类载入,开始进入父类B,设这个暂停点为0号位。同样,在载入父类B的过程中,发现父类B继承于Object类,那么父类B也暂停,开始进入Object类。此刻暂停点设置为。进入Object类,开始载入其中的静态变量并且退回到1号位。同样开始对父类B进行静态初始化的载入。然后又退回到0号位,此时静态初始化载入子类。
此时,所有类载入成功。
创建类对象阶段:
如果创立这个类的对象。那么就会按照先后顺序对实例变量进行创建空间,并且赋予初值。然后才会开始执行构造方法进行对象的初始化。
假设此时创建的是A的对象,那么在执行这个构造方法之前,会首先递归调用这个A的父类的构造方法,然后到Object类的构造方法。
执行Object构造方法前,系统首先按照声明实例变量时指定的初始化动作和实例初始化块中的语句在该类定义中出现的顺序依次执行它们。再执行构造方法中的语句
回归到父类B的构造方法,如果 某个构造方法调用了父类的构造方法,那么再开始执行该构造方法中的后续语句前,系统首先按照声明实例变量时指定的初始化动作和实例初始化块中的语句在该类定义中出现的顺序依次执行它们.再执行构造方法中后续语句。否则(使用this调用所属类的另外一个构造方法),直接执行后续语句
方法覆盖
方法覆盖就是方法中除了形参名是不同的,其他都是相同的。是在父类和子类之间。
与方法覆盖不同
Final
final 类似C中const 便是不可更改的意义。通常用来完成常量的定义。
Final变量
系统不会给final变量给与初值。所以final变量一定在要类中进行初始化。
final静态变量必须在声明的同时初始化(即定义常量)或者在静态初始块中初始化,对于final实例变量,也必须在声明的同时初始化(即定义常量),或在实例初始块中进行初始化,或者是在构造方法中进行初始化。
Final方法
特点:不可被继承
不能用关键字final进行修饰。
Final类
断子绝孙Final类。
其中所有变量和方法都是Final
用于标准库,如java.Math
对象类型转换
子类可以向上转换。
父类一般不可向下转换。除非,
类似这种.原本对象值就是引用的父类,只不过多了一重转换而已
1 | class C extends B{ |
多态和多态绑定
通过方法覆盖,系统根据具体的方法选择使用哪个方法的能力
多态转换会具有良好的封装性。比如以下代码
1 | public class TestPolymorphism{ |
这样makeSpeak();有良好的封装性