2015-07-20 35 views
0

考慮下面的C++程序:模板和泛型。爲什麼我可以在C++中執行以下操作,但不能在Java中執行以下操作?我如何克服這一點?

#include <iostream> 
using namespace std; 

template<typename T> 
class example 
{ 
    public: 
    void function (T a) 
    { 
     std::cout<<a.size(); 
    } 
}; 

int main() { 
    example<string> a; // this doesn't 
    string b = "a"; 
    //example<int> a; This gives an error 
    a.function (b); 
    // your code goes here 
    return 0; 
} 

現在考慮下面的Java程序:

import java.util.ArrayList; 

class example<T> { 

    public void function (T a) 
    { 
     System.out.println (a.toHexString(5)); /* this does not compile even when T is Integer */ 
    } 


} 

public class Main 
{ 
    public static void main (String[] args) 
    { 
     example<Integer> a = new example<Integer>(); 
     Integer b = 2; 
     a.function(b); 

     return; 
    } 
} 

我已經majorly是一個C++開發者到現在爲止和我學習Java的工作目的。所以,從模板工作的背景來看,泛型讓我感到困惑。

編輯我的問題:

在上述C++代碼,代碼編譯和如果我通過字符串作爲模板參數運行良好,因爲串確實有一個尺寸()方法。如果我使用int作爲模板參數,那麼可以理解,我會得到一個錯誤。這裏需要注意的是,如果我傳遞了一個名爲size()的方法的模板參數,C++允許我編譯和運行代碼。

但是,在Java代碼中,即使當我將Integer作爲通用參數(?是一個術語?)傳遞給Integer時,它也必須使用HexString(int)方法,但程序仍然無法編譯。它返回一個錯誤:

cannot find symbol 

這裏有什麼問題?什麼阻止我在Java中實現這種行爲?

編輯:此問題已被標記爲另一個問題可能重複: How do I call a method of a generic type object? 我會複製粘貼到我的反應爲什麼我認爲這個問題的不同。 上面的問題'潛在'告訴我如何擺脫錯誤。我問的是什麼阻止我在Java中實現上述效果?上述問題給了我這種疾病的藥物,而不是原因。

我在## java上提了一個類似的問題,聽說有一個新術語 - 物化。我想知道這是否與此有關?

+0

@Dukeling:不完全。上面的問題「可能」告訴我如何擺脫錯誤。我問的是什麼阻止我在Java中這樣做?上述問題給了我這種疾病的藥物,而不是原因。 – Paagalpan

+0

您標記的線不是導致錯誤的線。 – davmac

+0

@davmac:已更正。 – Paagalpan

回答

2

Java泛型通過類型擦除實現。當你有這樣的類簽名:

class example<T> { } 

該類被編譯爲一個普通的Java類。爲此,T有效地採用其上界的類型,在這種情況下爲Object。如果你有一個方法,如在你的榜樣作用,用T類型的參數:

public void function (T a) 

......那麼這就是,在這個函數編譯,幾乎一樣具有參數點類型爲Object。因此,您不能在參數上調用諸如toHexString的方法,因爲該方法未在Object中定義。

另一方面,在C++中,當模板被實例化時,會發生大量的符號解析,而不是首次編譯時。這是關鍵的區別;在Java中,泛型類被編譯爲字節碼,所以在編譯泛型類時(也就是說,編譯器必須能夠決定方法來自哪個類或接口)必須解析方法調用等。在C++中,當編譯器遇到模板時,它不會嘗試解析引用或產生目標代碼,除非和直到模板被實例化。

另一種思考方式:在Java中,example<String>example<Integer>都是通過相同的類實現的。在C++中,它們將是兩個獨立的類(都是由模板實例化而來)。

事實上,這就是爲什麼Java泛型類不是「模板」。在C++中,類模板允許實例化類(即,它用作從中創建類的模板)。在Java中,泛型類允許通過類單個類來實現參數化類型。

Java泛型類可以被認爲非常類似於類型參數(例如T)被替換爲綁定類型的非泛型類(Object,除非另有說明) - 主要區別在於編譯器將當你調用一個類的實例(它有一個帶有類型參數的完整類型,這樣T映射到其他類型)的方法時,執行額外的類型檢查,並且將有效地插入類型轉換(這樣你就可以調用一個返回T,通過引用將T映射到某種類型,而不必強制返回類型)。

1

問題是,Java泛型沒有像C++模板,也從來沒有這樣設計過。 Java泛型被設計爲一個特定的目標 - 在編譯時添加強類型檢查。因此,您可以找到以下近似Java版本。

interface Hex { 

    public String toHexString(int length); 
} 

class Example<T extends Hex> { 

    public void function(T a) { 
     System.out.println(a.toHexString(5)); 
    } 

} 

class StringWithHex implements Hex { 

    @Override 
    public String toHexString(int length) { 
     return "Hex"; 
    } 

} 

public void test() { 
    Example<StringWithHex> e = new Example<>(); 
    e.function(new StringWithHex()); 
} 

看看它只是確保類型匹配。

相關問題