如何限制方法只接受具有某些限制的参数?

时间:2014-12-03 01:08:08

标签: java generics

我有以下Duple类,我试图编写方法来对其两个"单元格进行数学运算。 ((new Duple(1,2)).plus(new Duple(2,6) == new Duple(3,8))

final class Duple<T,U> {
    final T a;
    final U b;
            public Duple(T a, U b) { this.a = a; this.b = b; }

    public String toString() {
        return "(" + a + ", " + b + ")";
    }

    /*public Duple<T,U> plus(Duple <T,U> otherDuple) {
        return Duple(a + otherDuple.a, b + otherDuple.b);
    }*/

注释掉的代码会出错,因为它无法保证TU支持+。有没有办法让它对参数进行编译时检查?

我试过了:

public Duple<T,U> plus(Duple <T extends Number,U extends Number> otherDuple) { ... }

但是编译器抱怨我要删除extends。我看到了一个使用用户定义接口的例子,但是对于我需要的东西,这看起来很极端。

基本上我试图模仿:

plus :: (Num t, Num u) => Duple t u -> Duple t u -> Duple t u
(x1,y1) `plus` (x2,y2) = (x1 + x2,y1 + y2)

如果它是用Haskell编写的

2 个答案:

答案 0 :(得分:1)

您不能拥有仅存在于您的类的某些实例中的方法。

相反,您可以将约束放在类的类型参数上。

答案 1 :(得分:1)

在Java中实现这一点并不是一个好方法。该语言不支持任何类型的&#34;添加&#34;或&#34;加&#34;适用于Number的任意子类的函数。

然而,我发现了一种相当黑客的解决方法。它要求您设置一个映射,将您感兴趣的每个数字类映射到一个函数,该函数将添加该类的两个数字,然后在运行时查找该函数。这使用Java 8:

final class Duple<T,U> {
    final T a;
    final U b;
    public Duple(T a, U b) { this.a = a; this.b = b; }

    public String toString() {
        return "(" + a + ", " + b + ")";
    }

    private static Map<Class,BinaryOperator> adders = new HashMap<>();

    private static <T> void setAdder(Class<T> forClass, BinaryOperator<T> adder) {
        adders.put(forClass, adder);
    }

    private static void setAdders() {
        setAdder(Integer.class, (x, y) -> x + y);
        setAdder(Long.class, (x, y) -> x + y);
        setAdder(Float.class, (x, y) -> x + y);
        setAdder(Double.class, (x, y) -> x + y);
        setAdder(BigInteger.class, (x, y) -> x.add(y));
        // add more as desired
    }

    static {
        setAdders();
    }

    private static <T1> T1 add(T1 x, T1 y) {
        BinaryOperator adder = adders.get(x.getClass());
        if (adder == null) {
            throw new RuntimeException("No plus operation defined for class");
        }
        return (T1)adder.apply(x, y);
    }

    public Duple<T,U> plus(Duple <T,U> otherDuple) {
        return new Duple(add(this.a, otherDuple.a), add(this.b, otherDuple.b));
    }

}

我的测试程序:

public static void main(String[] args) {
    Duple<Long,Double> x1, x2, x3;
    Duple<Float,BigInteger> x4, x5, x6;
    x1 = new Duple<>(3L, 4.0);
    x2 = new Duple<>(6L, 2.2);
    x3 = x1.plus(x2);
    System.out.println(x3);

    x4 = new Duple<>(1.7F, BigInteger.valueOf(15));
    x5 = new Duple<>(3.1F, BigInteger.valueOf(22));
    x6 = x4.plus(x5);
    System.out.println(x6);
}

并且输出是您所期望的:

(9, 6.2)
(4.8, 37)

(这使用了一些原始类型,但我不知道如何解决这个问题。)