或許大家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的錯誤了.