复用类之二
带参数的构造器
对于那些没有默认构造器,或者想调用一个带参的构造器的情况下,就必须用到super关键字显示的调用构造器。
class Game{
Game(int i){
System.out.println(“Game constructor”);
}
}
class BoardGame extends Game{
BoardGame(int i){
super(i);
System.out.println(“BoardGame constructor”)
}
}
public class Chess extends BoardGame{
Chess(){
super(11);
System.out.println(“Chess constructor”);
}
public static void main(String[] args){
Chess x=new Chess();
}
}
输出
Game constructor
BoardGame constructor
Chess constructor
如果不写super显示调用的话,基类将无法初始化,因此,调用基类构造器必须是你在导出类构造器中要做的第一件事。
代理
代理是一种介于继承和组合之间的中庸之道,java没有为其提供直接的支持。
public class SpaceShipControls{
void up(int velocity){}
void down(int velocity){}
void left(int velocity){}
void right(int velocity){}
void forward(int velocity){}
void back(int velocity){}
void turboBoost(){}
}
public class SpaceShip extends SpaceShipControls{
private String name;
public SpaceShip(String name){this.name=name;}
public String toString(){return name;}
public static void main(String[] args){
SpaceShip protector=new SpaceShip(“NSEA Protector”);
protector.forward(100);
}
}
上面的例子使用继承让SpaceShip类可以得到SpaceShipControls的方法,但是与此同时SpaceShipControls中的所有方法都在SpaceShip中暴露了出来,可以使用代理来处理此问题。
public class SpaceShipDelegation{
private String name;
private SpaceShipControls controls=new SpaceShipControls();
public SpaceShipDelegation(String name){
this.name=name;
}
public void back(int velocity){
controls.back(velocity);
}
public void down(int velocity){
controls.down(velocity);
}
public void forward(int velocity){
controls.forward(velocity);
}
public void left(int velocity){
controls.left(velocity);
}
public void right(int velocity){
controls.right(velocity);
}
public void turboBoost(){
controls.turboBoost();
}
public void up(int velocity){
controls.up(velocity);
}
public static void main(String[] args){
SpaceShipDelegation protector=
new SpaceShipDelegation(“NSEA protecor”);
protector.forward(100);
}
}
代理类将参数传给controls对象,因此可以看出代理类拥有更多的控制性,同时也保护了类的结构。
保持正确的清理
虽然java中有垃圾回收机制,但是你并不知道垃圾回收期何时将会被调用,或者它是否将被调用。因此,如果你想要清理一些东西,就必须显示地编写一些代码。
class Shape{
Shape(int i){System.out.println(“Shape constructor”);}
void dispose(){System.out.println(“Shape dispose”);}
}
class Circle extends Shape{
Circle(int i){
super(i);
System.out.println(“
}
void dispose(){
System.out.println(“Erasing Circle”);
super.dispose();
}
}
class Triangle extends Shape{
Triangle(int i){
super(i);
System.out.println(“Drawing Triangle”);
}
void dispose(){
System.out.println(“Erasing Triangle”);
super,dispose();
}
}
class Line extends Shape{
private int start,end;
Line(int star,int end){
super(start);
this.start=start;
this.end=end;
System.out.println(“Drawing Line:”+start+”,”+end);
}
void dispose(){
System.out.println(“Erasing Line:”+start+”,”+end);
super.dispose();
}
}
public class CADSystem extends Shape{
private Circle c;
private Triangle t;
private Line[] lines=new Line[3];
public CADSystem(int i){
super(i+1);
for(int j=0;j<lines.length;j++)
lines[i]=new Line(j,j+j);;
c=new Circle(1);
t=new Triangle(1);
System.out.println(“Combined constructor”);
}
public void dispose(){
System.out.println(“CADSystem.dispose()”);
t.dispose();
c.dispose();
for(int i=lines.length-1;i>=0;i--)
line[i].dispose();
super.dispose();
}
public static void main(String[] args){
CADSystem x=new CADSystem(47);
try{
}finally{
x.dispose();
}
}
}
输出
Shape constructor
Shape constructor
Drawing Line:0,0
Shape constructor
Drawing Line:1,1
Shape constructor
Drawing Line:2,4
Shape constructor
Drawing Circle
Shape constructor
Drawing Triangle
Combined constructor
CADSytem.dispose()
Erasing Triangle
Shape dispose
Erasing Circle
Shape dispose
Erasing Line:2,4
Shape dispose
Erasing Line:1,1
Shape dispose
Erasing Line:0,0
Shape dispose
需要注意在析构函数中,应首先执行类的所有特定的清理动作,其顺序同生成顺序相反,然后就可以调用基类的清理方法了。
在大多数情况下并不涉及到清理,但是如果需要进行清理应尽量使用自编清理方法,而不要使用finalize()。
名称屏蔽
如果在已经在基类中存在一个被多次重载的方法名称,那么导出类中重新定义该方法名称并不会屏蔽其在积累中的任何版本。因此,无论是在该层或它的基类中对方法进行定义,重载机制都可以正常工作
class Homer{
char doh(char c){
System.out.println(“doh(char)”);
return ‘d’;
}
float doh(float f){
System.out.print(“doh(float)”);
return 1.0f;
}
}
class Milhouse{}
class
void doh(Milhouse m){
System.out.println(“doh(Milhouse)”);
}
}
public class Hide{
public static void main(String[] args){
Bart b=new Bart();
b.doh(1);
b.doh(‘x’);
b.doh(1.0f);
b.doh(new Milhouser());
}
}
输出
doh(float)
doh(char)
doh(float)
doh(Milhouse)
可见虽然Bart中导入了新的重载方法,但是基类中的方法依然可用。
Java SE5新增加了@Override注释,他并不是关键字,但是可以把它当做关键字使用。当你想要覆盖某个方法时,可以标上这个注释、
class lisa extends Homer{
@Override void doh(Milhouse m){
System.out.println(“doh(Milhouse)”);
}
}
@Override可以在你不想重载时使用。
向上转型
在新类中定义新特性并不是继承技术最重要的特点,其最重要的特点是用来表现新类和基类关系。可以说新类是现有类的一种类型。
class Instrument{
public void play(){}
static void tune(Instrument i){
///….
i.play(i);
}
}
public class Wind extends Instrument{
public static void main(String[] args){
Wind flute=new Wind();
Instrument.tune(flute);
}
}
在此例中tune()方法接收了Wind引用,鉴于Java对类型的检测十分严格,接收某种类型的方法对象可以接受另一种类型就会显得很奇怪,除非你认识到Wind对象也是一种Instrument对象,而且也不存在任何tune()方法是可以通过Instrument来调用,同时又不存在与Wind之中。tune()中,程序代码可以对Instrument和他的导出类起作用,这种将Wind引用转换为Instrument引用的动作,称之为向上转型。