c++模板與java範型的區別。

       因爲本人以前是c++程序員,如今轉行成了java程序員,因此在學習java的時候,感受和c++很像,特別是java的設計者也曾說,設計這麼靈感主要來自於c++,因此看到類似的地方老是要來總結一番的。java

1.java泛型的概念

       其實咱們在編寫類和方法的時候,咱們通常使用的是具體的類型(要麼是基本的類型,要麼是自定義的類,)而用泛型可使類型參數化,這樣就能夠編寫更通用的代碼,能夠應用於多種類型的代碼。ios

2.c++模板的概念

       編寫帶有參數化類型的通用版本,讓編譯器自動生成針對不一樣類型的具體版本。c++

 

       java泛型最主要的目的就是用來指定容器要持有什麼類型的對象,並且有編譯器來保證類型的正確性。程序員

3.c++模版和java泛型的區別

      3.1c++模板可使用基本類型(int、short、long),而java泛型不能使用基本類型作類型參數。(爲何)學習

      3.2.java在使用泛型的時候不會知道具體的類型信息,可是c++是能夠知道的。spa

          由於:java泛型是經過擦除實現的,這意味着你在使用泛型的時候,任何具體的類型信息都沒擦除掉了。你惟一知道的就是你在使用一個對象。所以List<string>和List<Interger>在運行時實際上是一個類型,兩種都會被擦除爲其原生的類型List。設計

          示例 c++code

//: generics/Templates.cpp
#include <iostream>
using namespace std;

template<class T> class Manipulator {
  T obj;
public:
  Manipulator(T x) { obj = x; }
  void manipulate() { obj.f(); }
};

class HasF {
public:
  void f() { cout << "HasF::f()" << endl; }
};

int main() {
  HasF hf;
  Manipulator<HasF> manipulator(hf);
  manipulator.manipulate();
} /* Output:
HasF::f()
///:~

這個代碼是能夠正確運行的,在Manipulator類裏面存儲了T類型的對象,而後在manipulate裏面調用的T對象的f()方法,它是怎麼知道f()方法是參數類型T的呢?對象

   答:當你實例化這個模版的時候,c++編譯器將進行檢查。他在實例化Manipulator<HasF> manipulator(hf)的這一刻,它看到HasF有一個方法f()。因此c++中,當模版實例化的時候,模板代碼知道其模版參數的類型。ip

可是在java中

class Manipulator<T> {
  private T obj;
  public Manipulator(T x) { obj = x; }
  // Error: cannot find symbol: method f():
  public void manipulate() { obj.f(); }
}

public class Manipulation {
  public static void main(String[] args) {
    HasF hf = new HasF();
    Manipulator<HasF> manipulator =
      new Manipulator<HasF>(hf);
    manipulator.manipulate();
  }
} ///:~

編譯會報錯,

       由於java編譯器沒法將manipulator裏面的可以在obj上調用f()方法的這一需求映射到HasF擁有f()方法這一事實上。因此java是不知道具體的類型信息的。爲了解決這個問題,要使用到泛型邊界,以此告知編譯器只能接受遵循這個邊界的類型。

代碼以下

class Manipulator2<T extends HasF> {
    private T obj;
    public Manipulator2(T x) { obj = x; }
    public void manipulate() { obj.f(); }
} ///:~

       邊界<T extends HasF> 聲明瞭T是從HasF導出的類型或具備類型HasF,因此就能夠在Obj上面調用f()了。

       上面的效果其實就是編譯器會把參數類型替換成他的擦除,就像上面的案例。T擦除到了HasF,就好像在類的聲明中用HasF替換了T同樣。變成以下:

class Manipulator3 {
    private HasF obj;
    public Manipulator3(HasF x) { obj = x; }
    public void manipulate() { obj.f(); }
} ///:~

       使用擦除的緣由:擦除的核心動機是它使得泛型化的客戶端能夠調用非泛型化的類庫來使用。反之亦然。其實就是「遷移兼容性」。若是沒有某種遷移兼容性,全部已經構建很長時間的類庫就須要與但願遷移到java泛型上的開發者們說再見了。類庫是很重要的,他們對生產效率會產生重要的影響。所以這不是一個能夠接受的代價。

相關文章
相關標籤/搜索