java:关于泛型结构的谜题

时间:2013-08-19 19:10:57

标签: java generics structure

我有一个关于结构创建的难题:一个表示一般物理变换的接口变换,以及一个表示特定变换类型的类PoincareTransform。我想做这样的事情

public interface Transform {
   public Transform compose(Transform t);
}

public class PoincareTransform implements Transform {
   private Matrix matrix;
   public Transform compose(Transform t) {
   ...
   }
}

但是我希望那个方法组合(变换T)只采用PoicareTransform,因为必须有一个矩阵来组合。一种可能的解决方案是使用泛型

public interface Transform<T extends Transform<T>> {
   public T compose(T t);
}

public class PoincareTransform implements Transform<PoincareTransform> {
   private Matrix matrix;
   public PoincareTransform compose(PoincareTransform t) {
   ...
   }
}

但这并不令人满意,因为它在概念上并不干净,优雅并且再次出现问题:PoincareTransform子类现在具有与以前相同的问题。另外,根据这个定义,我的项目周围都有泛型!

我在概念上是错的?我怎么能建立一个我想到的这样的结构?

2 个答案:

答案 0 :(得分:0)

我想我会选择你的第一个解决方案,但如果你无法从PoincareTransform.transform(Transform t)中的给定转换中获得矩阵,则会返回错误。

例如:

public class PoincareTransform implements Transform {
   private Matrix matrix;
   public Transform compose(Transform t) {
     if (!t.hasMatrix()) {
       // Throw an exception, or some other meaningful error.
     }
     ...
   }
}

这样,它是通用的,所以如果你最终使用矩阵进行不同类型的变换,那么你可以使用它。

另一方面,如果您真的只想操作PoincareTransforms,可以使用instanceof运算符检查传入的实例是否正确。

public class PoincareTransform implements Transform {
   private Matrix matrix;
   public Transform compose(Transform t) {
     if (!t instanceof PoincarTransform) {
       // Throw an exception, or some other meaningful error.
     }
     PoincarTransform p = (PoincarTransform)t;
     ...
   }
}

答案 1 :(得分:0)

你在谈论协变参数类型,我不相信你可以在java的类型系统中编码。它会违反Liskov的原则:如果超类型声明它可以接受某种类型T的值,那么子类型必须至少接受它。 (但允许的是逆变量参数类型:子类型可以接受更多类型而不是其超类型(在您的情况下,Liskov将允许PoincoreTransform.compose接受对象而不是变换),但这又是AFAIK在java中不受支持。)

恕我直言,最干净的解决方案是放弃编译时间检查并解决运行时检查的想法:在子类型中使用instanceof以确保参数具有正确的Transform子类型(如我前面的海报所示)