2012-06-02 62 views
3

我想寫一個數學向量的類(保持實數)。我認爲矢量運算幾乎與矢量維無關,所以不是編寫類如Vector2D,Vector3D,Vector4D,...我只想寫一個Vector類。任意維度的數學向量的一個類

現在的問題是我不能乘以2D矢量與4D之一,所以我想到了一個字段dimension。但是現在我不得不爲每一個操作檢查它,所以我問自己是否可以做得比這更好。這就是我腦海中的泛型。但是,有一次我不得不這樣做Vector<? extends Dimension>,其中Dimension簡直是一個基類的Dimension.OneDimension.Two等,這意味着,我必須寫一個Dimension類每一個層面我想用vectos。

所以我的問題:

有沒有辦法編寫任意維矢量的一個類,而不必在運行時檢查維?

+0

我更新了我的答案和工作實現。這可能是矯枉過正,但它顯示瞭如何完成。 – Eric

回答

2

如果我正確理解你的問題,那麼答案是你不能同時擁有兩個。無論是使用類型系統來確保正確的維度,然後最終導致顯式類型氾濫(泛型不會幫助您),或者使用狀態來跟蹤維度並在每次執行操作時執行動態檢查。 由於矢量的「維度」是它保存了多少個元素,因此這將在底層數據結構中以某種方式表示。例如,如果您使用列表將值存儲在向量中,則列表知道它包含的元素數量。所以做一個簡單的運行時檢查很便宜,並且當維度不匹配時可以拋出異常。與基於類型的解決方案相比,該解決方案更靈活且易於編程。

+0

+1「便宜... [和] ...易於編程。」這有真正的價值。 –

+0

我這麼認爲,但希望我只是錯過了一些東西。 – IchBinKeinBaum

0

你可以寫一個Vector類有一些有趣的仿製藥

public static class Vector<V extends Vector<V>>{ 
    protected double[] components; 
    public final int dimensions; 
    private Class<V> klass; 

    protected Vector(int d, Class<V> klass) { 
     this.klass = klass; 
     this.components = new double[d]; 
    } 

    public double get(int x) { return components[x] } 
    protected void set(int x, double d) { components[x] = d } 

    public V clone() { 
     try { 
      V c = klass.newInstance(); 
      c.components = this.components.clone(); 
      return c; 
     } 
     catch(InstantiationException e1) {} 
     catch(IllegalAccessException e2) {} 
     return null; 
    } 

    public V add(V that) { 
     V sum = this.clone(); 
     for(int i = 0; i < dimensions; i++) 
      sum.components[i] += that.components[i]; 
     return sum; 
    } 

} 

然後得出每種情況下:

public static class Vector2D extends Vector<Vector2D>{ 
    public Vector2D() { 
     super(2, Vector2D.class); 
    } 
    public Vector2D(double x, double y) { 
     this(); 
     set(0, x); 
     set(1, y); 
    } 
} 
public static class Vector3D extends Vector<Vector3D>{ 
    public Vector3D() { 
     super(3, Vector3D.class); 
    } 
    public Vector3D(double x, double y, double z) { 
     this(); 
     set(0, x); 
     set(1, y); 
     set(2, z); 
    } 
} 
public static class Vector4D extends Vector<Vector4D>{ 
    public Vector4D() { 
     super(4, Vector4D.class); 
    } 
    public Vector4D(double w, double x, double y, double z) { 
     this(); 
     set(0, w); 
     set(1, x); 
     set(2, y); 
     set(3, z); 
    } 
} 

畢竟,有特殊情況 - 例如,交叉產品僅存在於3維和7維中。每個解決方案都有一個實現。

+0

不幸的是OP仍然需要在運行時測試每種方法的維度。 – Howard

+0

@霍華德:不正確。 OP將使用'Vector3D'的實例,它保證有三個維度。嘗試實現Vector.add方法時出現問題。 – Eric

+0

我有一些類似的想法,但我仍然必須爲每個維度編寫類。 – IchBinKeinBaum

2

如果向量不兼容,則可以在Dimension類中嵌入執行檢查的方法並拋出Runtime Exception。然後用Dimension中的每個方法調用這個方法。現在代碼使用Dimension類將不會被檢查。

0

要清楚爲什麼我想使用泛型(它的工作原理這就是爲什麼我張貼它作爲一個答案):

Dimension.java:

public class Dimension { 
    class ONE extends Dimension {} 
    class TWO extends Dimension {} 
    class THREE extends Dimension {} 
    // [...] 
} 

Vector.java:

public class Vector<D extends Dimension> { 
    private double[] elements; 

    public Vector(double _elmts) { 
     elements = _elmts; 
    } 

    public void add(Vector<D> v) { /*...*/ } 
    public void subtract(Vector<D> v) { /*...*/ } 
} 

但正如我的問題中提到的,我必須創建幾個類,這是我想要預防的第一個地方。這也相當醜陋。除了信任用戶之外,沒有辦法確保elements具有正確的維度。

我想這與埃裏克的答案非常相似。

+0

您在Dimension類中所做的事情基本上是Java在爲您定義枚舉類時自動爲您做的。但是無論你在那裏做什麼,總有人會想要使用比你所允許的維度更高的矢量。 – Wormbo

+0

此版本不允許您實現非變異方法 – Eric

相關問題