《Java编程思想》 第8章 多态

第8章 多态

1、在面向对象的程序设计语言中,多态是继数据抽象和继承之后的第三种基本特征。它通过动态绑定(后期绑定或运行时绑定),允许使用基对象但却在调用函数时实现其真实子对象的功能。

2、使用多态的注意事项:多态只在普通方法中起作用

  • 对于private方法或final方法,由于不存在继承因此此类方法是在编译时就直接绑定的。即使在子类中重新编写了相同的方法,编译器也认为其实它是子类的一个全新的方法,从而也就不可能实现多态的特征。
  • 对于静态方法,由于其并不是与具体的对象而是与对应类相关联,因此也无法表现出多态。
  • 域:在子类中可以理解为包含一个基类对象,因此对应的子类和基类的域在空间中分配了不同的存储空间,可以通过this和super进行分别引用。同时,将子类传递给基类,如果使用基类对象访问域也将返回基类的域。

3、构造器与多态

class Glyph{
	void draw(){System.out.println("Glyph.draw");}
	Glyph(){
		System.out.println("Glyph() before draw()");
		draw();
		System.out.println("Glyph() after draw()");
	}
}

class RoundGlyph extends Glyph{
	private int radius = 1;
	RoundGlyph(int r){
		radius = r;
		System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius);
	}
	void draw(){
		System.out.println("RoundGlyph.draw(), radius = " + radius);
	}
}

public class PloyConstructors{
	public static void main(String[] args){
		new RoundGlyph(5);
	}
}/*Output
Glyph() before draw()
RoundGlyph.draw(), radius = 0
Glyph() after draw()
RoundGlyph.RoundGlyph(), radius = 5
*///:~

由于在基类构造器中由于多态需要调用子类的draw函数,但此时子类中的普通域还没有初始化,但由于“在其他任何事物发生之前,将分配给对象的存储空间初始化为二进制零”,因此当时“radius=0”。可以理解为域中的初始化语句还没有执行,但对应空间已被初始化。

编写构造器时有一条有效的准则:“用尽可能简单的方法使对象进入正常的状态;如果可以的话,避免调用其他方法”。

4、向下转型:运行时类型识别(Runtime Type Identification, RTTI)

有时,只有一个基类对象,其实质其实是一个子类对象,而又想调用子类中基类没有的借口,通常需要对基类对象进行向下转型。但Java在运行时总是会对类型进行检查,因此如果将本是基类的对象强制类型转换为子类对象,即使只访问基类中的接口同样将在运行时抛出异常。

class TestMain{
	void draw(){}
}

public class Test extends TestMain{
	void draw(){System.out.println("draw");}
	void drawTest(){System.out.println("drawTest");}
	public static void main(String[] args){
		TestMain t1 = new Test();
		//t1.drawTest(); // method not found
		((Test)t1).drawTest();
		TestMain t2 = new TestMain();
		((Test)t2).draw();
	}
}/*Output
drawTest
Exception in thread "main" java.lang.ClassCastException: TestMain cannot be cast to Test
	at Test.main(Test.java:14)
*///:~


你可能感兴趣的:(Java基础)