方法覆盖
Java SE5中新增加了 @Override 注解,它虽非关键字,但可以用作关键字。当编写程序想要覆盖某方法时可以选择添加,在不小心将方法重载而非注释时,编辑器将会报错。
protected关键字
它指明“就类用户而言,这是private”,但对于任何继承与此类的导出类(子类)或其他位于同一包内的类来说,它是可以访问的。
构造器内部的多态方法的行为
在一般方法内部,动态绑定的调用是在运行时才决定的,因为对象无法知道它是属于方法所在的那个类,还是属于那个类的导出类。
如果要调用构造器内部的一个动态绑定方法,就要用到那个方法的被覆盖后的定义。然而这个调用的效果可能难以预料,因为被覆盖的方法在对象被完全构造前就会被调用。这可能会造成一些难以发现的隐藏错误。
public class test { public static void main(String[] args) { new RoundGlyph(5); } } 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.raduis= "+radius); } void draw() { System.out.println("RoundGlyph.draw().radius= "+radius); } }
运行结果:
Glyph.draw()方法设计为将要被覆盖,这种覆盖是在RoundGlyph中发生的。但Glyph构造器会调用这个方法,结果调用的是Round Glyph.draw()方法。但查看输出结果,当Glyph调用draw()方法时,radius不是默认的初始值1,而是0。
我们需要知道初始化的实际过程:
这种情况可以在基类中对方法声明final避免,导出类的覆盖是真的完全覆盖啊(当然也可以用super再调用)!
向下转型
由于向上转型(将导出类的参数带入参数类型为基类的方法)会丢失具体类型的信息。但向上转型是安全的,因为基类不会具有大于导出类的接口。在Java中所有转型都会得到检查,包括进行一次普通的加括弧形式的类型转换,确保得到的是我们需要的那种类型,否则将返回ClassCastException(类转型异常)
class useful { public void f(){System.out.println("f() in useful");} public void g(){System.out.println("g() in useful");} } class more_useful extends useful { public void f(){System.out.println("f() in more useful");} public void g(){System.out.println("g() in more useful");} public void u(){System.out.println("u() in more useful");} } public class test { public static void main(String[] args) { useful[] x= {new useful(),new more_useful()}; x[0].f(); x[1].g(); //x[1].u(); 这是不被允许的 try { ((more_useful)x[1]).u(); ((more_useful)x[0]).u(); } catch(ClassCastException e) { System.out.println("向下转型失败!"); } } }
运行结果:
more_useful继承自useful,所以可以向上转型到useful类型,数组中两个对象都属于useful类型,调用f()、g()方法都是许可的,但如果调用u()方法就会编译失败。如果想再使用,可以尝试向下转型,如果所转类型是正确的,那么转型成功,否则将抛出一个ClassCastException异常。
个人认为,向下转型是为了允许基类数组中存在子类,且允许子类能“反悔”调用扩展的成员方法。
[1] Bruce Eckel.Java编程思想[M].陈昊鹏,北京:机械工业出版社出版社.2007