[英]Passing generic class type in java
我正在嘗試看看是否可以在Java中模仿模板表達模式,以進行諸如循環融合的優化。
例如,我將在此表達式模板示例中找到的c ++類移植到java類: https : //en.wikipedia.org/wiki/Expression_templates#Motivation_and_example
首先,代表向量表達式的模板類VecExpression<E>
。 它使用一個模板參數E
並采取了類類型的E
作為構造函數的參數。 然后,它創建一個私有變量thisAsE
設置this
類型E
的類類型
public abstract class VecExpression <E> {
private VecExpression thisAsE;
public VecExpression(Class<E> type) throws Exception {
if(type.isInstance(this)) {
thisAsE = (VecExpression)type.cast(this);
}
else {
throw new Exception("Class type must extend VecExpression");
}
}
public double get(int i) {
return thisAsE.get(i);
}
public int size() {
return thisAsE.size();
}
}
第二,一類Vec
延伸VecExpression<Vec>
其中通過Vec.class
進入超級構造和實現get()
和size()
方法調用在VecExpression<E>
類。
public class Vec extends VecExpression<Vec> {
private double[] elems;
public <E> Vec(VecExpression<E> expression) throws Exception {
super(Vec.class);
for(int i = 0; i < expression.size(); ++i) {
elems[i] = expression.get(i);
}
}
public Vec(double[] elems) throws Exception {
super(Vec.class);
this.elems = elems;
}
public double get(int i) {
return elems[i];
}
}
第三,模板類VecSum<E1, E2>
擴展了VecExpression<VecSum<E1, E2>
,並使用其get()
方法返回兩個VecExpression<E>
的和。 該類型作為顯式參數Class<VecSum<E1, E2>> type
傳遞。
public class VecSum <E1, E2> extends VecExpression<VecSum<E1, E2>> {
private VecExpression u;
private VecExpression v;
public VecSum(Class<VecSum<E1, E2>> type, VecExpression<E1> u, VecExpression<E2> v) throws Exception {
super(type);
if(u.size() != v.size()) {
throw new Exception("Vectors must be of the same size");
}
this.u = u;
this.v = v;
}
public double get(int i) {
return u.get(i) + v.get(i);
}
public int size() {
return v.size();
}
}
最后,我們使用表達式模板來生成一個類,該類可以一次通過內存添加三個向量。
public class Main {
public static void main(String[] args) throws Exception {
Vec a = new Vec(new double[] {1, 2, 3});
Vec b = new Vec(new double[] {1, 2, 3});
Vec c = new Vec(new double[] {1, 2, 3});
VecSum<Vec, Vec> ab = new VecSum<Vec, Vec>(VecSum<Vec, Vec>.class, a, b);
VecSum<VecSum<Vec, Vec>, Vec> abc = new VecSum<>(VecSum<VecSum<Vec, Vec>, Vec>.class, ab, c);
}
}
根據Louis Wasserman的評論進行編輯
但是,傳遞給VecSum
構造函數的類類型不起作用,因為表達式試圖從參數化類型中獲取類。 Louis指出,泛型類的實現不會像在c ++中那樣編譯為不同的類。 您將如何傳遞它們的類型,或者對表達模板模式有另一種方法?
您嘗試做的事情在Java中不起作用,至少在您試圖通過使用Java泛型來獲得編譯時優化方面。 原因是,與C ++模板不同,Java泛型在編譯時無法解析。 由於編譯器沒有在編譯時解析類型,因此它無法使用任何有關其的信息來進行編譯時優化。 從某種意義上說,由Java編譯器創建的字節碼以另一種方式完全“擦除”通用信息。 如果您的Java類是class C<A>
則在代碼中到處出現類型A
地方,都將其替換為Object
類。 如果您的Java類是class D<E extends F>
則代碼中E
出現的所有地方都將替換為F
在這種情況下,您可能會問為什么要使用泛型。 答案是,在編譯器丟棄參數之前,它會對輸入進行類型安全檢查,並隱式地對方法返回值插入強制類型轉換。 這是在Java的幾個版本中增加的一種便利,但是Java容器類(如ArrayList
存在。 只是因為您沒有像現在這樣的類型安全性,因為輸入是顯式的Object
(即使您知道該對象僅包含String
對象並強制使用它,也可以放入任何對象)以將get
的結果顯式轉換為String
)。
這與C ++模板相反,在C ++模板中,編譯器從模板創建類定義並編譯該類。 然后可以將該類作為任何其他類進行編譯,包括潛在地使用特定於模板參數值的優化。 此外,C ++中的模板專業化允許更廣泛地進行模板元編程,因為它允許您為模板參數的遞歸創建基礎。
(由於上述原因,您在Java中不能具有任何類似的“通用專業化”含義-Java編譯器已經拋出了通用參數,因此您的“專用”類(如果您嘗試定義這樣的事情)將是與“通用”類相同。)
最后,關於您的示例,請記住,Java中以大寫字母“ C”表示的Class
與其他任何類一樣的類,包括它從Object
派生的。 這並不能解決C ++模板與Java泛型之間在編譯時與運行時之間的差異。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.