或许大家java的多态问题,对上溯,下溯造型有了一定的概念,对PRotected和private大家想必也很清楚,但是,这几个个结合在一起,往往令人产生很多困惑,在这里,我举一个例子,大家或许会发觉这篇文章对你来说还是很有意义的: 例子一共有两个class. 可能出现困惑的地方我都会在后面一一解释. A是一个父类,B继续A,并且实现了protectedTest(Object obj)方法.如下面所示: B.java的源代码: package cn.org.matrix.test; import cn.org.matrix.test.A; /** * <p>Title: protect, private and upcasting </p> * <p>Description: email:chris@matrix.org.cn</p> * <p>Copyright: Matrix Copyright (c) 2003</p> * <p>Company: Matrix.org.cn</p> * @author chris * @version 1.0,who use this example pls remain the declare */ public class B extends A { protected int protectedb = 0; protected int protectedab = 0;
public static void main (String[] args) { // Test A A a1 = new A(); a1.privateTest(); // Test B String helloStr = "Hello"; Object helloObj = helloStr; B b1 = new B(); A a2 = b1; // 这里发生了什么?困惑1 b1=a1; //编译错误,困惑2 b1. privateTest(); //编译错误,困惑3 b1.protectedTest(helloObj); //输出结果?困惑4 b1.protectedTest(helloStr); //编译错误,困惑5 a2.protectedTest(helloObj); //输出结果? 困惑6 a2.protectedTest(helloStr); //输出结果?困惑7 ? } }
困惑2: A a2 = b1是可以的,但是为什么b1=a1却是不行? 在这里,我们依然可以套用上面的两条规则,我们可以看到,b1是类B的一个引用,a1既不是类B的实例,也不是类B的子类的实例,所以直接b1=a1就出现了编译错误. 假如确实需要进行这样的转化,我们可以这样作:b1=(B)a1; 进行强制转化,也就是下溯造型. 在java里面,上溯造型是自动进行的,但是下溯造型却不是,需要我们自己定义强制进行.
困惑3: b1. privateTest();编译不通过? 这是很显然的,你可以回顾一下private的定义: 私有域和方法只能被定义该域或方法的类访问. 所以,在这里,b1不能访问A的方法privateTest(),即使b1是A的子类的实例. 请看下面的例子: public class A { private int two(int i) { return i; } } class Test extends A { public static void main(String[] args) { System.out.println(A.two(3)); } }
而protected则不同,我们回顾一下protected的定义: 被保护的域或方法只能被类本身、类的子类和同一 程序包中的类所访问。 下面是一个错误使用protected的例子: package cn.org.matrix.test; public class ProtectedTest { protected void show() { System.out.println("I am in protected method"); } }
import cn.org.matrix.test.*; public class Test { public static void main (String[] args) { ProtectedTest obj = new ProtectedTest(); obj.show(); } } 因为访问权限问题,你会得到”show() has protected access in test.ProtectedTest”的出错信息.
困惑5: b1.protectedTest(helloStr); 这里为什么会出现编译错误? 他可以调用类B的protectedTest(Object obj)方法啊,把helloStr上溯造型成一个object就行了啊..或者上溯造型到A然后调用A的protectedTest(helloStr)方法啊. 呵呵,问题的根源就在于此了,既然有两种选择,jvm应该选择那一种?这种不确定性假如交给jvm来动态决定的话,势必带来程序的不确定性..虽然java在其他的一些地方也有类似的情形出现,比如static变量的循环定义造成的不确定性,但是,在这里,jvm还是在编译阶段就解决了这个问题. 所以,我们会在这一步碰到编译错误: “reference to protectedTest is ambiguous; both method protectedTest(java.lang.String) in mytest.A and method protectedTest(java.lang.Object) in mytest.B match at line 46. 在这里,我们碰到的是显式的reference ambiguous错误,但是,有时候,隐式的reference ambiguous却往往是更加的危险. 在这里,我举个例子: 父类的 源代码: public super { private void test(int i, long j); { System.out.println(i+”and”+j); } } 子类的源代码: public sub { private void test(long j, int i); { System.out.println(i+”and”+j); } }
子类和父类都用有相同名称的方法test,参数类型不同而已.这种情况下,编译可以被通过. 但是假如你在另外一个类中用到了如下代码: Sub sb = new Sub(); sb.test(100, 3000); 你就会碰到编译错误,因为没有确定的指出3000的类型,所以造成reference ambiguous的错误了.