2+ 类 实现通用接口的高级 Java 习语
Advanced Java idiom for 2+ classes implementing a generic interface
我遇到了以下情况,想知道我实现它的方式在可重用性和速度方面是否很好,我也有兴趣拥有一个实际的可编译解决方案,因为下面的解决方案无法编译(我希望有人能找到罪魁祸首,并对此有一个简单而优雅的想法。
有两个 Java classes "Vec3F" 和 "Vec3" 实现了浮点和双精度类型的基本矢量数学。两者都实现如下接口:
public final class Vec3 implements Vec<Vec3> {
//..
public double distance(Vec3 other) { /*..*/ }
}
public interface Vec<V> {
double distance(V other);
}
我这样做是为了让一些算法能够与两种类型的向量实现一起工作,但问题来了:
public class Toolbox {
public static <T> double getAllDistances(List<Vec<T>> points) {
Vec<T> prevPoint = points.get(0);
Vec<T> point;
double sum = 0.0;
int len = points.size();
for (int i=1;i<len; i++) {
point = points.get(i);
//-> this doesn't compile:
//The method distance(T) in the type Vec<T> is not applicable for the arguments (Vec<T>)
sum+=point.distance(prevPoint);
prevPoint = point;
}
return sum;
}
}
我知道我可以实现 'getAllDistances' 两次,但这是我想避免的。我希望有一个工具箱 class 可以根据接口中声明的方法执行一些元算法。
我还想避免更改例如的方法实现distance(Vec3 other) 传递接口(因为它直接使用例如 other.x*other.x 以避免调用任何 getter)。
我很高兴对此有一些想法,希望问题足够清楚和具体,提前致谢!
我想我找到了一种类型安全的方法:
public static <T extends Vec<T>> double getAllDistances(List<T> points) {
T prevPoint = points.get(0);
T point;
double sum = 0.0;
int len = points.size();
for (int i=1;i<len; i++) {
point = points.get(i);
sum+=point.distance(prevPoint);
prevPoint = point;
}
return sum;
}
这通过在参数中远离 List < Vec < T> > 并将其定义为 T 的边界来解决编译器问题。
除了冗长的方法声明外,它对我来说看起来非常简单和直观。
您可能希望将 Vec 接口定义为:
public interface Vec<V extends Vec<V>>
这可能很难看,乍一看像是非法的前向引用,但它是完全有效和正常的(实际上在 java.lang.Enum 中使用)。
只要您有一个 Vec<T>
实例,就必须将 T
而不是 Vec<T>
传递给 distance
方法。所以你需要像这样定义你的 getAllDistances 方法:
public static <T extends Vec<T>> double getAllDistances(List<T> points) {
T prevPoint = points.get(0);
T point;
我遇到了以下情况,想知道我实现它的方式在可重用性和速度方面是否很好,我也有兴趣拥有一个实际的可编译解决方案,因为下面的解决方案无法编译(我希望有人能找到罪魁祸首,并对此有一个简单而优雅的想法。
有两个 Java classes "Vec3F" 和 "Vec3" 实现了浮点和双精度类型的基本矢量数学。两者都实现如下接口:
public final class Vec3 implements Vec<Vec3> {
//..
public double distance(Vec3 other) { /*..*/ }
}
public interface Vec<V> {
double distance(V other);
}
我这样做是为了让一些算法能够与两种类型的向量实现一起工作,但问题来了:
public class Toolbox {
public static <T> double getAllDistances(List<Vec<T>> points) {
Vec<T> prevPoint = points.get(0);
Vec<T> point;
double sum = 0.0;
int len = points.size();
for (int i=1;i<len; i++) {
point = points.get(i);
//-> this doesn't compile:
//The method distance(T) in the type Vec<T> is not applicable for the arguments (Vec<T>)
sum+=point.distance(prevPoint);
prevPoint = point;
}
return sum;
}
}
我知道我可以实现 'getAllDistances' 两次,但这是我想避免的。我希望有一个工具箱 class 可以根据接口中声明的方法执行一些元算法。 我还想避免更改例如的方法实现distance(Vec3 other) 传递接口(因为它直接使用例如 other.x*other.x 以避免调用任何 getter)。
我很高兴对此有一些想法,希望问题足够清楚和具体,提前致谢!
我想我找到了一种类型安全的方法:
public static <T extends Vec<T>> double getAllDistances(List<T> points) {
T prevPoint = points.get(0);
T point;
double sum = 0.0;
int len = points.size();
for (int i=1;i<len; i++) {
point = points.get(i);
sum+=point.distance(prevPoint);
prevPoint = point;
}
return sum;
}
这通过在参数中远离 List < Vec < T> > 并将其定义为 T 的边界来解决编译器问题。 除了冗长的方法声明外,它对我来说看起来非常简单和直观。
您可能希望将 Vec 接口定义为:
public interface Vec<V extends Vec<V>>
这可能很难看,乍一看像是非法的前向引用,但它是完全有效和正常的(实际上在 java.lang.Enum 中使用)。
只要您有一个 Vec<T>
实例,就必须将 T
而不是 Vec<T>
传递给 distance
方法。所以你需要像这样定义你的 getAllDistances 方法:
public static <T extends Vec<T>> double getAllDistances(List<T> points) {
T prevPoint = points.get(0);
T point;