簡體   English   中英

在Java中傳遞通用類類型

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM