或許大家java的多態(tài)問(wèn)題,對(duì)上溯,下溯造型有了一定的概念,對(duì)PRotected和private大家想必也很清楚,但是,這幾個(gè)個(gè)結(jié)合在一起,往往令人產(chǎn)生很多困惑,在這里,我舉一個(gè)例子,大家或許會(huì)發(fā)覺(jué)這篇文章對(duì)你來(lái)說(shuō)還是很有意義的: 例子一共有兩個(gè)class. 可能出現(xiàn)困惑的地方我都會(huì)在后面一一解釋. A是一個(gè)父類,B繼續(xù)A,并且實(shí)現(xiàn)了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; // 這里發(fā)生了什么?困惑1 b1=a1; //編譯錯(cuò)誤,困惑2 b1. privateTest(); //編譯錯(cuò)誤,困惑3 b1.protectedTest(helloObj); //輸出結(jié)果?困惑4 b1.protectedTest(helloStr); //編譯錯(cuò)誤,困惑5 a2.protectedTest(helloObj); //輸出結(jié)果? 困惑6 a2.protectedTest(helloStr); //輸出結(jié)果?困惑7 ? } }
困惑2: A a2 = b1是可以的,但是為什么b1=a1卻是不行? 在這里,我們依然可以套用上面的兩條規(guī)則,我們可以看到,b1是類B的一個(gè)引用,a1既不是類B的實(shí)例,也不是類B的子類的實(shí)例,所以直接b1=a1就出現(xiàn)了編譯錯(cuò)誤. 假如確實(shí)需要進(jìn)行這樣的轉(zhuǎn)化,我們可以這樣作:b1=(B)a1; 進(jìn)行強(qiáng)制轉(zhuǎn)化,也就是下溯造型. 在java里面,上溯造型是自動(dòng)進(jìn)行的,但是下溯造型卻不是,需要我們自己定義強(qiáng)制進(jìn)行.
困惑3: b1. privateTest();編譯不通過(guò)? 這是很顯然的,你可以回顧一下private的定義: 私有域和方法只能被定義該域或方法的類訪問(wèn). 所以,在這里,b1不能訪問(wèn)A的方法privateTest(),即使b1是A的子類的實(shí)例. 請(qǐng)看下面的例子: 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的定義: 被保護(hù)的域或方法只能被類本身、類的子類和同一 程序包中的類所訪問(wèn)。 下面是一個(gè)錯(cuò)誤使用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(); } } 因?yàn)樵L問(wèn)權(quán)限問(wèn)題,你會(huì)得到”show() has protected access in test.ProtectedTest”的出錯(cuò)信息.
困惑5: b1.protectedTest(helloStr); 這里為什么會(huì)出現(xiàn)編譯錯(cuò)誤? 他可以調(diào)用類B的protectedTest(Object obj)方法啊,把helloStr上溯造型成一個(gè)object就行了啊..或者上溯造型到A然后調(diào)用A的protectedTest(helloStr)方法啊. 呵呵,問(wèn)題的根源就在于此了,既然有兩種選擇,jvm應(yīng)該選擇那一種?這種不確定性假如交給jvm來(lái)動(dòng)態(tài)決定的話,勢(shì)必帶來(lái)程序的不確定性..雖然java在其他的一些地方也有類似的情形出現(xiàn),比如static變量的循環(huán)定義造成的不確定性,但是,在這里,jvm還是在編譯階段就解決了這個(gè)問(wèn)題. 所以,我們會(huì)在這一步碰到編譯錯(cuò)誤: “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錯(cuò)誤,但是,有時(shí)候,隱式的reference ambiguous卻往往是更加的危險(xiǎn). 在這里,我舉個(gè)例子: 父類的 源代碼: 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,參數(shù)類型不同而已.這種情況下,編譯可以被通過(guò). 但是假如你在另外一個(gè)類中用到了如下代碼: Sub sb = new Sub(); sb.test(100, 3000); 你就會(huì)碰到編譯錯(cuò)誤,因?yàn)闆](méi)有確定的指出3000的類型,所以造成reference ambiguous的錯(cuò)誤了.