熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Javascript >> 正文

Java中引用,造型等問題解析

2013-11-23 17:56:53  來源: Javascript 

  作者chris譯
  
   或許大家java的多態問題對上溯下溯造型有了一定的概念對protected和private大家想必也很清楚但是這幾個個結合在一起往往令人產生很多困惑在這裡我舉一個例子大家或許會發覺這篇文章對你來說還是很有意義的:
  

  例子一共有兩個class 可能出現困惑的地方我都會在後面一一解釋A是父類B繼承A並且實現了protectedTest(Object obj)方法如下面所示:
  


  

  Bjava的源代碼:


  

  package matrixtest;

   import matrixtestA;

   /**

   * <p>Title: protect private and upcasting </p>

   * <p>Description: email:</p>

   * <p>Copyright: Matrix Copyright (c) </p>

   * <p>Company: </p>

   * @author chris

   * @version who use this example pls remain the declare

   */

   public class B extends A

   {

   protected int protectedb = ;

   protected int protectedab = ;

  


  

  protected void protectedTest(Object obj)

   {

   Systemoutprintln("in BprotectedTest(Object):" + obj);

   }

   }

  


  

  Ajava的源代碼:


  

  package matrixtest;

   import matrixtestB;

   /**

   * <p>Title: protect private and upcasting </p>

   * <p>Description: email:</p>

   * <p>Copyright: Matrix Copyright (c) </p>

   * <p>Company: </p>

   * @author chris

   * @version who use this example pls remain the declare

   */


  

  public class A

   {

   protected int protecteda = ;

   protected int protectedab = ;

   private void privateTest()

   {

   Systemoutprintln("in AprivateTest()");

   }

   protected void protectedTest(Object obj)

   {

   Systemoutprintln("in AprotectedTest(Object):" + obj );

   }

  

   protected void protectedTest( String str )

   {

   Systemoutprintln("in AprotectedTest(String):" + str);

   }

  

   public static void main (String[] args)

   {

   // Test A

   A a = new A();

   aprivateTest();

   // Test B

   String helloStr = "Hello";

   Object helloObj = helloStr;

   B b = new B();

   A a = b; // 這裡發生了什麼?困惑

   b=a; //編譯錯誤困惑

   b privateTest(); //編譯錯誤困惑

   bprotectedTest(helloObj); //輸出結果?困惑

   bprotectedTest(helloStr); //編譯錯誤困惑

   aprotectedTest(helloObj); //輸出結果? 困惑

   aprotectedTest(helloStr); //輸出結果?困惑 ?

   }

   }

  


  

  下面我來逐個解釋每一處困惑的地方:


  

  困惑


  

  這裡其實就是子類自動上溯造型到父類A這裡a其實是指向了一個B類型的對象 我們通常都可以這樣作: A a=b 這樣作的意思實際上就是讓a指向了一個類型B的對象—在這裡就是b
  


  

  在java裡面關於跨類引用有兩條規則應該記住:


  

   如果a是類A的一個引用那麼a可以指向類A的一個實例或者說指向類A的一個子類


  

   如果a是接口A的一個引用那麼a必須指向實現了接口A的一個類的實例


  

  所以根據這兩個規則我們就不難理解例子中的A a = b是什麼意思了


  

  困惑:


  

  A a = b是可以的但是為什麼b=a卻是不行? 在這裡我們依然可以套用上面的兩條規則我們可以看到b是類B的一個引用a既不是類B的實例也不是類B的子類的實例所以直接b=a就出現了編譯錯誤
  


  

  如果確實需要進行這樣的轉化我們可以這樣作:b=(B)a; 進行強制轉化也就是下溯造型 在java裡面上溯造型是自動進行的但是下溯造型卻不是需要我們自己定義強制進行
  


  

  困惑:


  

  b privateTest();編譯不通過? 這是很顯然的你可以回顧一下private的定義: 私有域和方法只能被定義該域或方法的類訪問所以在這裡b不能訪問A的方法privateTest()即使b是A的子類的實例請看下面的例子
  


  

  public class A

   {

   private int two(int i) { return i; }

   }

   class Test extends A {

   public static void main(String[] args) {

   Systemoutprintln(Atwo());

   }

   }

  


  

  Systemoutprintln(Atwo());這行編譯出錯顯然因為private方法不能在這個類之外被訪問而protected則不同我們回顧一下protected的定義:
   被保護的域或方法只能被類本身類的子類和同一程序包中的類所訪問


  

  下面是一個錯誤使用protected的例子:


  

  package matrixtest;

   public class ProtectedTest {

   protected void show() {

   Systemoutprintln("I am in protected method");

   }

   }


  

  import matrixtest*;

   public class Test {

   public static void main (String[] args) {

   ProtectedTest obj = new ProtectedTest();

   objshow();

   }

   }

  


  

  因為訪問權限問題你會得到show() has protected access in testProtectedTest的出錯信息


  

  困惑:


  

  bprotectedTest(helloObj); 輸出的是in BprotectedTest(Object):… 這到底是為什麼呢?
   為什麼jvm能夠確定是輸出B的方法而不是A的方法? 這就和jvm的運行機制有關系了 我們上面提到了a是一個A類型的引用但是指向了一個B類型的實例
   在這裡如果jvm根據引用的類型在這裡就是A 來定義調用哪個方法的話那麼應該是調用A的protectedTest(helloObj)


  

  然後實際上不是這樣的因為jvm的動態編譯能力jvm會在runtime來決定調用哪一個method而不是在compile time 也就是所謂的latebinding(runtime)和earlybinding(compiletime)
  


  

  困惑:


  

  bprotectedTest(helloStr); 這裡為什麼會出現編譯錯誤? 他可以調用類B的protectedTest(Object obj)方法啊把helloStr上溯造型成一個object就行了啊或者上溯造型到A然後調用A的protectedTest(helloStr)方法啊
  


  

  呵呵問題的根源就在於此了既然有兩種選擇jvm應該選擇那一種?這種不確定性如果交給jvm來動態決定的話勢必帶來程序的不確定性雖然java在其他的一些地方也有類似的情形出現比如static變量的循環定義造成的不確定性但是在這裡jvm還是在編譯階段就解決了這個問題
  


  

  所以我們會在這一步遇到編譯錯誤: reference to protectedTest is ambiguous; both method protectedTest(javalangString)
   in mytestA and method protectedTest(javalangObject) in mytestB match at
   line


  

  在這裡我們遇到的是顯式的reference ambiguous錯誤但是有時候隱式的reference ambiguous卻往往是更加的危險我舉個例子:
  


  

  父類的源代碼:


  

  public super

   {

   private void test(int i long j);

   {

   Systemoutprintln(i+and+j);

   }

   }

  


  

  子類的源代碼:


  

  public sub

   {

   private void test(long j int i);

   {

   Systemoutprintln(i+and+j);

   }

   }

  


  

  子類和父類都用有相同名稱的方法test參數類型不同而已這種情況下編譯可以被通過


  

  但是如果你在另外一個類中用到了如下代碼:


  

  Sub sb = new Sub();

   sbtest( );

  


  

  你就會遇到編譯錯誤因為沒有確定的指出的類型所以造成reference ambiguous的錯誤了


  

  困惑


  

  aprotectedTest(helloObj);

  


  

  輸出結果分別是in Bp
From:http://tw.wingwit.com/Article/program/Java/Javascript/201311/25404.html

    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.