用于 2 个以上实现通用接口的类的高级 Java 习惯用法

问题描述 投票:0回答:2

我遇到了以下情况,想知道我实现它的方式在可重用性和速度方面是否良好,我也有兴趣拥有一个实际的可编译解决方案,因为下面的解决方案无法编译(我希望有人找到罪魁祸首并对此有一个简单而优雅的想法)。

有两个 Java 类“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”两次,但这是我想避免的。我希望有一个 Toolbox 类,它可以根据接口中声明的方法执行一些元算法。 我还想避免改变例如的方法实现distance(Vec3 other) 来传递接口(因为它直接使用 other.x*other.x 以避免调用任何 getter)。

我很高兴对此有一些想法,并希望问题足够清晰和具体,提前致谢!

java algorithm generics typesafe
2个回答
4
投票

您可能想将 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;

4
投票

我想我找到了一种类型安全的方法:

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 的边界来解决编译器问题。 除了冗长的方法声明之外,它对我来说看起来非常简单和直观。

© www.soinside.com 2019 - 2024. All rights reserved.