2013-07-25 71 views
2

我有一個關於java中對象引用的概念性問題。創建對象的引用

這裏Num是一個接口

public interface Num { 
    void sum(); 
} 

NUM2它實現貨號

public class Num2 implements Num{ 
    @Override 
    public void sum() { 
     System.out.println(getRandom()+getRandom()); 
    } 

    public int getRandom() { 
     Random randomNumber = new Random(); 
     int number = randomNumber.nextInt(30); 
     return number; 
    } 
} 

和主函數

Num n = new Num2(); 
n.sum(); 

在這裏,我知道Ñ是對象的基準Num2和n是一個指向對象Num2的指針。 NUM2既包含了方法總和getRandom。但是,當我們試圖通過ň引用來訪問方法,我們只能得到總和方法。我的問題是,指針如何知道Num中包含哪種方法。在對象初始化過程中,如何以及在堆棧中存儲哪些信息以供參考。如果我有任何誤解糾正了我。

回答

1

我認爲下面那張背後(糾正我,如果我錯了):

當你創建一個參考Num n,然後在某處這是通過其屬性創建的內存。

所以它必須定義方法和可以通過這個引用訪問的東西。

現在,當您將它引用到對象時,該對象就是內存中的一個單獨的實體。當您嘗試使用引用進行訪問時,編譯器必須使用引用元數據來確定使用該引用可以調用哪個方法等等。

+0

對於阿布......正確的+1。 –

+0

@Abu創建和獲取引用的屬性是否在編譯時發生?你能否詳細說明這些分配是如何在編譯和運行時發生的。 –

1

您只能訪問定義爲變量的類型的方法編譯時間。由於您的n變量來自Num類型,因此您只能使用Num界面中定義的方法。請注意,這些方法的行爲將由實際對象引用類型定義,在本例中爲Num2

2

編譯器(而不是在運行時)負責驗證的,你把你的物體,像Num而非Num2

3

您所定義的變量nNum類型的接口,因此你只能在調用方法在Num中聲明。我相信這個解決方案是在編譯時間本身完成的。編譯器通過使用基於類型的引用變量來確定可訪問的字段或方法。

但請記住,運行時將調用實際對象類型的方法,即實現接口的類。

類類型T的變量可以保存一個空引用,或T級的或任何類的實例的引用是T.

請看下面的代碼的子類:

interface A { 
    void method1(); 
} 
class B implements A { 
    public void method1() { 
    } 
    public void methodB(){ 
    } 
} 
class C implements A { 
    public void method1() { 
    } 
    public void methodC(){ 
    } 
} 
public class InterfaceTest { 
    public void testMethod(A a){ 
     // this is safe because whatever may be the run time type of actual 
     // object `a` is referring to , that object will always implement 
     // method1. 
     a.method1(); 
     // this cannot be allowed because compiler doesn't know 
     // what will be the actual run time object `a` will refer to 
     // It may or may not be an object of B. 
     a.methodB(); 
    } 
} 
+0

如何編譯器實際上看到它的視角的參考?@The新白癡 –

+0

@DiptopolDam正如我已經強調上述JLS,編譯器檢查的參考變量的類型,並確定哪些方法可以使用引用變量調用。 – NINCOMPOOP

1
My question is that how can a pointer know which method are contained in Num? 

在編譯時它只會檢查引用指針調用的函數或方法是否在引用指針類中聲明(不一定定義)。在運行時,整個繼承樹以自頂向下的方式進行解析,並選擇正確的函數實現。

另外,您提到的引用指針在堆棧中,而實際對象在堆中。和對象有它的類information.Let我舉一個例子 -

Animal animal = new Dog(); 
    System.out.println(animal.getClass()); 

將打印class Dogclass Animal

0

在java中,當Child extends Parent(或implements)和你寫Parent object = new Child(),已創建了Parent參照存儲器中的Child對象。

一旦代碼被編譯時,JVM將處理內存中的對象,它會知道引用變量object實際上指的是在內存Child類型的對象(在你的情況,nNum2型) 。

但是在那之前,你必須處理編譯器。該編譯只關心參考,在這種情況下是Parent的類型(或你的情況Num),這樣只會讓你取消它的方法,這些方法在Parent聲明(Num)類。得到這個各地

一種方法是做一個演員,就像這樣:

((Num2) n).getRandom();

確保只有做到這一點,如果你肯定知道n是(或將要)實際上指向一個內存中的對象Num2!否則,您將獲得ClassCastException
在這裏,你告訴編譯器:「相信我,我知道這是一個Num2,所以把它當作一個。」

綜上所述:

  • Num n = new Num2()聲明一個參考變量,並創建一個對象在內存
  • 該變量是Num型的,這就是所有的編譯器知道
  • 在存儲器中創建的對象是鍵入Num2,並且JVM將知道這個
  • 要運行JVM,您必須滿足編譯器
  • 在這種情況下,您可以通過強制轉換來滿足編譯器。