如何实例化泛型类型?
How do I instantiate a generic type?
我正在为 Java 中的一个项目做一些数学运算 classes。我有一个 Vector3 class,但我还需要 Vector4 和 Vector2,但显然我不想复制粘贴我的代码 3 次。
所以我所做的是一个 Vector class,它将成为所有向量的母亲 class。我可以只使用没有 child 的 Vector class,但我更喜欢使用这些 child class,因为我可以在它们上面添加特定的东西,比如 Vector3 中的欧拉角操作而且我想使用 Vector4 作为四元数的母 class。无论如何,这是我简化的 Vector class:
public class Vector {
public double[] values;
public Vector(double[] values) {
this.values = values;
}
public int getLength() {
return values.length;
}
public static <T extends Vector> T multiply(T vector, double k) {
double[] values = new double[vector.getLength()];
for(int i = 0; i < values.length; i++)
values[i] = k* vector.values[i];
return new T(values);
}
}
public class Vector3 extends Vector {
public Vector3(double[] values) {
super(values);
}
}
问题是编译器不让我实例化一个 T:"Type parameter T cannot be instantiated directly"。但是我需要这个 T 因为我需要返回的向量与发送的向量类型相同。
如果我执行 new Vector2(4,2).multiply(42),我需要得到一个 Vector2 而不是一个 Vector。我还可以在 Vector2 中创建一个乘法方法,调用 Vector multiply,然后复制 Vector2 中的值,但是 1. 这太糟糕了,2. 这意味着 child 向量之间有很多复制粘贴,3. 我需要性能,所以这并不理想。
我知道我可以使用反射来解决问题,但这些方法对性能至关重要,所以我必须尽可能简单。
我还考虑过更改参数中的向量,这样我就不必实例化一个新的向量,但这是一个非常糟糕的主意,因为它会导致奇怪的行为。
感谢任何帮助。
如果它对性能至关重要,您实际上可能会考虑让 multiply 方法改变向量的状态,而不是创建一个新的向量。在我看来,这并不奇怪,只要它是确定性的和记录在案的行为即可。
但是,对于不可变向量 class,您需要 clone
向量。
public class Vector implements Cloneable {
// not a good idea to make it public, if you don't want any changes here
private double[] values;
public static <T extends Vector> T multiply(T vector, double k) {
Vector temp = vector.clone();
for(int i = 0; i < temp.values.length; i++)
temp.values[i] = k * temp.values[i];
// the clone method guarantees that 'temp' is of type T,
// but since it is not generic, the compiler cannot check it
@SuppressWarnings("unchecked")
T result = (T)temp;
return result;
}
protected Vector clone() {
try {
Vector vector = (Vector)super.clone();
vector.values = Arrays.copyOf(values, values.length);
return vector;
} catch (final CloneNotSupportedException exc) {
// this is a weird design choice of `Object.clone()`, too,
// but back then, we did not have annotations or anything equivalent
throw new AssertionError("we forgot to implement java.lang.Cloneable", exc);
}
}
}
最简单的方法似乎是在 Vector
class:
上有一个实例方法
Vector make(double[] values) {
return new Vector(values);
}
然后在每个子 class 中重写,使用协变 return 类型:
class Vector3 extends Vector {
//...
@Override Vector3 make(double[] values) {
return new Vector3(values);
}
//...
}
然后您可以在乘法方法中调用它。
return vector.make(values);
但老实说,我不会尝试将向量的长度编码为类型。当你需要一个包含 57032 个元素的向量时会发生什么?您肯定不想为此创建一个特定的 class ,对吗?如果 Vector
的两个不同子 class 具有相同数量的元素,会发生什么情况:它们是否兼容(例如添加)?
更自然地处理向量的语言(例如 MATLAB)不会将其构建到类型中;问问自己你是否真的需要它。
我正在为 Java 中的一个项目做一些数学运算 classes。我有一个 Vector3 class,但我还需要 Vector4 和 Vector2,但显然我不想复制粘贴我的代码 3 次。
所以我所做的是一个 Vector class,它将成为所有向量的母亲 class。我可以只使用没有 child 的 Vector class,但我更喜欢使用这些 child class,因为我可以在它们上面添加特定的东西,比如 Vector3 中的欧拉角操作而且我想使用 Vector4 作为四元数的母 class。无论如何,这是我简化的 Vector class:
public class Vector {
public double[] values;
public Vector(double[] values) {
this.values = values;
}
public int getLength() {
return values.length;
}
public static <T extends Vector> T multiply(T vector, double k) {
double[] values = new double[vector.getLength()];
for(int i = 0; i < values.length; i++)
values[i] = k* vector.values[i];
return new T(values);
}
}
public class Vector3 extends Vector {
public Vector3(double[] values) {
super(values);
}
}
问题是编译器不让我实例化一个 T:"Type parameter T cannot be instantiated directly"。但是我需要这个 T 因为我需要返回的向量与发送的向量类型相同。
如果我执行 new Vector2(4,2).multiply(42),我需要得到一个 Vector2 而不是一个 Vector。我还可以在 Vector2 中创建一个乘法方法,调用 Vector multiply,然后复制 Vector2 中的值,但是 1. 这太糟糕了,2. 这意味着 child 向量之间有很多复制粘贴,3. 我需要性能,所以这并不理想。
我知道我可以使用反射来解决问题,但这些方法对性能至关重要,所以我必须尽可能简单。
我还考虑过更改参数中的向量,这样我就不必实例化一个新的向量,但这是一个非常糟糕的主意,因为它会导致奇怪的行为。
感谢任何帮助。
如果它对性能至关重要,您实际上可能会考虑让 multiply 方法改变向量的状态,而不是创建一个新的向量。在我看来,这并不奇怪,只要它是确定性的和记录在案的行为即可。
但是,对于不可变向量 class,您需要 clone
向量。
public class Vector implements Cloneable {
// not a good idea to make it public, if you don't want any changes here
private double[] values;
public static <T extends Vector> T multiply(T vector, double k) {
Vector temp = vector.clone();
for(int i = 0; i < temp.values.length; i++)
temp.values[i] = k * temp.values[i];
// the clone method guarantees that 'temp' is of type T,
// but since it is not generic, the compiler cannot check it
@SuppressWarnings("unchecked")
T result = (T)temp;
return result;
}
protected Vector clone() {
try {
Vector vector = (Vector)super.clone();
vector.values = Arrays.copyOf(values, values.length);
return vector;
} catch (final CloneNotSupportedException exc) {
// this is a weird design choice of `Object.clone()`, too,
// but back then, we did not have annotations or anything equivalent
throw new AssertionError("we forgot to implement java.lang.Cloneable", exc);
}
}
}
最简单的方法似乎是在 Vector
class:
Vector make(double[] values) {
return new Vector(values);
}
然后在每个子 class 中重写,使用协变 return 类型:
class Vector3 extends Vector {
//...
@Override Vector3 make(double[] values) {
return new Vector3(values);
}
//...
}
然后您可以在乘法方法中调用它。
return vector.make(values);
但老实说,我不会尝试将向量的长度编码为类型。当你需要一个包含 57032 个元素的向量时会发生什么?您肯定不想为此创建一个特定的 class ,对吗?如果 Vector
的两个不同子 class 具有相同数量的元素,会发生什么情况:它们是否兼容(例如添加)?
更自然地处理向量的语言(例如 MATLAB)不会将其构建到类型中;问问自己你是否真的需要它。