本章更多讨论了子类对父类的继承可能导致的各种陷阱,比如隐藏(hidden),遮蔽(shadow),遮掩(obscure),覆写(override),重载(overload)等行为。 1。首先来看看一个隐藏的例子: class Base { class Derived extends Base { public class PrivateMatter { 我们可能指望它打印Base,可很抱歉,此程序是无法编译通过,刚一看错误信息你可能愣住: 无权访问private的className。。。 对 于实例方法,子类可以对父类的实例方法进行覆写,可对于实例变量(而且包括类变量,静态方法,final静态变量),子类只能隐藏父类中的相同名称的变 量,而不是覆写。根据new Derived()的编译期类型为子类Derived,调用子类的className属性,可此属性是声明为private的,所以无法编译通过。如果我 们想调用父类中被隐藏的className,可以通过向上转型来实现: System.out.println(((Base)new Derived()).className); 此例告诉我们,JAVA语言中子类定义与父类相同类型和名称的变量、嵌套类型和静态方法,都将隐藏掉父类中相应的方法,而不是覆写,所以,请避免隐藏!此过程中当然也不存在所谓多态。另外,我们不应该违反这样一条规则:对基类所做的任何行为,都应当可以同样作用于子类。此例中子类className为private,违反了基类中className是public的定义,这样的写法应该避免。
2。也许哪一天你突然想自己写一个String来代替java.lang中的String,让我们来看看会发生什么? public class StrungOut { class String { public String(java.lang.String s) { public java.lang.String toString() { StrungOut dose not have a main method! 怪了,明明有个main方法啊??请注意,main方法中的参数String []args,其中的String类型要求是java.lang.String,可JVM会自动地把把这些参数认为是我们自定义的下面那个String类型,这就是错误的原因所在。教训:避免重用类名,特别是java平台的类型,特别是java.lang包下的类名!在此例中,当前类所在包中的所有类的main方法都将因此失效。 3。遮掩(obscure):我觉的翻译成模糊也许更好。看看下面的例子: public class ShadesOfGray { class X { static C Y = new C(); class C { 你认为他应该打印什么呢??黑还是白?还是黑白不分:),光明的力量总是伟大,它一直打印的是:white。这说明了X.Y一直调用的是静态变量Y,而不是静态内隐类Y。JAVA语言规范告诉我们,当一个变量和一个类型具有相同的名字,明确他们位于相同的作用范围内,变量名具有优先权,同样,变量名与类型名将遮掩包名。 即 变量名>类型名>包名。其实上面的例子有更严重的问题,它并没有遵循标准的JAVA命名习惯,变量应该以小写开头(mixedCase的格 式),类名以大写开头(MaxedCase的格式),如果完全遵照习惯来写,就不会出现此问题了。所以,请遵守标准的命名习惯。退一步,假设在某些情况下 我们只能以此方式书写,那我们怎么访问静态内隐类Y呢?两种方法: System.out.println(((X.Y)null).Z); //借助表达式访问类变量,还记的吗? 在JDK5中还可以这样: public static <T extends X.Y> void main(String args[]){ //继承X.Y类解决此问题。 System.out.println(T.Z); }
4。 包A中的某个类被另一个包C中的子类所继承,如果子类当中“覆写”了父类中的方法,而此方法在父类中不是声明为public或者protected,那么 这并非覆写,这两个方法将没有任何关系。所以,如果你希望某个类的一个方法被包外的子类所覆写,请把此方法声明为protected或者public。 5。遮蔽(shadow),这里讨论了JDK5静态导入需要注意的问题,看下面的例子: import static java.util.Arrays.toString; class ImportDuty { static void printArgs(Object... args) { 6。最后一个谜题很重要哦,我现在才知道JDK5对条件操作符(a?b:c)已经有重大改变。试着分别在JDK1.4和JDK5中运行下面的程序: import java.util.Random; public class CoinSide { public static CoinSide flip() { public static void main(String[] args) { class Heads extends CoinSide { public String toString() { class Tails extends CoinSide { public String toString() { incompatible types for ?: neither is a subtype of the other 说什么第2个操作数和第3个操作数都不是另外一个子类。而在JDK5下这个程序将正常运行,随机打印heads或者tails。这是因为在JDK5以前,条件运算符要求:当第2个和第3个操作数是引用类型时,它们其中的一个必须是另外一个的子类。而例子中Heads和Tails都不是对方的子类,所以产生了上面的错误。而在JDK5中,这个条件放宽了,第2个和第3个操作数如果是引用那么都是合法的,只不过其结果类型将是这两种类型的最小公共超类。此例中Heads和Tails的超类向上追溯有CoinSide,Object,而CoinSide是他们的最小公共超类。 如果想在JDK5以前运行上面的程序,可以把第2或者第3操作数向上转型为他们的超类即可: public static CoinSide flip() { 另外一些谜题讨论了对Object类中方法的覆写问题,特别要注意不要覆写变成了重载 Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=728172 |
|
来自: ShangShujie > 《java》