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

引用 造型 protected和private的困惑

2013-11-15 09:48:57  來源: JSP教程 

  或許大家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 BprotectedTest(Object) 經過上面的解釋想必大家都能很清楚的知道為什麼會有這兩個輸出結果了aprotectedTest(helloObj);因為jvm的latebinding所以在runtime的時候調用了B類的方法雖然在編譯期間a只是一個父類A的引用類型
  
  困惑
    aprotectedTest(helloStr); 為什麼這裡會輸出 in AprotectedTest(Object)…為什麼這裡不會編譯出錯?為什麼b protectedTest(helloStr)會出錯而a protectedTest(helloStr)會出錯?我調用了aequals(b)和a==b得到的結果都是true啊?但是為什麼這裡出這個錯誤?
    在這裡這個問題是最關鍵的也是我們放到最後來解答的原因
    首先回顧一下equals()和==的在java裡面的概念記得有一道scjp
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19162.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.