多态,动态绑定机制,静态绑定机制
多态
多态:同一行为的不同表现形式
/*白话一点,用子类对象实例化父类*/
举个例子:
public static void main(String[] args) {
Person individual = new Student();
individual.speak();
Person indicidual_2 = new Teacher();
indicidual_2 = new Teacher();
indicidual_2.speak();
}
输出结果:
Student Speaks!
Teacher Speaks!
对与父类Person的Speak功能可以通过两个不同的子类实例Student和Teacher来进行不同的表示。
动态绑定机制
动态绑定机制,Java虚拟机将方法与当前调用对象的实际内存进行绑定
上例中,实例individual用Student对象进行时实例化,在进行方法调用时,由于动态绑定规则,将调用Student类里的speak()方法;同理,实例individual_2用Teacher对象实例化,所以进行方法调用是用的是Teacher对象中的speak()方法。
ps:动态绑定机制是建立在多态之上的,而且是针对对象的方法,与属性无关
由于多态和动态绑定规则,就决定了子类在对父类方法进行覆盖的时候
●子类方法不能更改父类方法的访问权限
●子类方法不能比父类方法抛出更多的异常
这些问题都不会在编译的时候报错,但是会在程序运行时导致异常终止
静态绑定机制
在编译阶段就能够确定方法在内存中的什么位置
所有私有方法、静态方法、构造器及final修饰方法都是采用静态绑定机制。在编译器阶段就已经指明了调用方法在常量池中的符号引用,JVM运行的时候只需要进行一次常量池解析即可
接口
Java没法多继承,但是可以是实现多个接口。
接口不能实例化,但是可以定义接口变量然后用实现了该接口的类对象来进行实例化,例如:
类Camera实现了接口Photographable,即Camera实现了拍照功能,下面的代码是可以的:
Photographable temp = new Camera();
它的用法在书的239页有一个应用。通过将接口与抽象类比较来体现这一功能的实际应用。
通过接口进行交互比用过抽象类进行交互能够获得更好的松耦合。
如下,定义了一个方法photograph来表示拍照
public void photograph(Camera tool, Target tar)
{
tool.takePhoto(tar);
}
该方法确实实现了拍照功能,但是不难体会得到,该方法只能表示用相机拍照,现实中还有其他的拍照工具,通过这一方法就没法一并实现;这是如果使用接口来表示拍照工具,就可以为实际应用保留更多的余地:
public void photograph(Photographable tool, Target tar)
{
tool.takePhoto(tar);
}
如此一来,所有实现了接口Photographable也就是有拍照功能的工具都可以作为参数传入函数。
系统交互里的接口和抽象类
接口作为系统之间交互的窗口
抽象类用来定制系统中的扩展点
举个例子,两个系统A,B如下:
系统A,B之间想要实现交互,例如,系统B中的Person希望用拍照设备进行拍照,就要通过系统A的接口Photograpgable来进行交互,具体的实现或许是通过系统B内的方法,引用Photograpgable类型的参数使用系统A中的设备;
但是对于系统B中的Device(并没有说明是怎样的设备,可能是任何功能的设备,我们假设他现在不具有拍照功能),如果说系统B希望在Device上扩展出拍照功能,可以使系统B中的某一个类来继承系统A中的抽象类,从而实现功能上的扩展;
更白话一点:如果一个人希望用拍照设备进行拍照,他就要通过拍照设备的接口来使用拍照设备;如果一个人想买人生中的第一讲可以拍照的设备(增加拍照的功能),就要通过继承抽象类。
适配器模式
关于构造方法
●每个构造函数开始之前都会默认调用父类的构造函数
●如果父类有显式声明的构造函数且没有无参构造函数:
■其子类必须显式的声明构造函数
■子类构造函数的第一句必须显式的调用父类的一个构造函数
否则都会导致编译错误
一个测试:
public static void main(String[] args) {
Student individual = new Student();
individual.speak();
}
输出结果:
异常
抛出异常
一个方法除了在定义时抛出异常外,还可以在捕获到final类型的时候在处理块中抛出,示例:
void method()
{
try{
throw new IOException();
}catch(final Exception E)
{
throw E;
}
}
保持异常的原子性
当一场发生的时候,各个对象的状态能够恢复到异常发生前,而不至于停留在某个不合理的中间状态
例如,在一个用于进行银行账户之间转账的函数,用户1的账户正常,被划走了100块,正准备打给用户2的时候发现用户2的用户处于关闭状态,最后用户1少了100而用户2没有多100,显然是一个不合理的中间状态。
为保持异常原子性,有下面几种方法:
●在进行可能导致异常的操作前,先对对象的状态进行检查,确保不会出现中间状态后在执行后续操作;
●准备专门的恢复代码,能够主动回到初始状态;
●先在对象的副本上进行操作,确保状态合理之后复制给对象。