在Java中,我可以指定任意数量的泛型类型参数吗?

时间:2015-11-06 14:31:27

标签: java generics

我希望在Java 中创建一种特定类型的接口(尽管这同样适用于常规类)。这个接口需要包含一些方法,比如invoke;它将使用不同数量的参数调用,具体取决于提供的泛型类型参数。

举个例子:

public interface Foo<T...> {
    public void invoke(T... args);
}

// In some other class
public static Foo<Float, String, Integer> bar = new Foo<Float, String, Integer>() {
    @Override
    public void invoke(Float arg1, String arg2, Integer arg3) {
        // Do whatever
    }
};

简要说明如何使用(并提供一些上下文),考虑一个类Delegator:该类采用不同数量的泛型类型,并且只有一个方法 - invoke,包含这些参数类型。该方法将其参数传递给列表中的对象:IDelegate的实例,它采用相同的泛型类型。这允许Delegator在几个委托方法(在IDelegate中定义)之间进行选择,而不必为每个特定的参数类型列表创建新类。

有这样的可用吗?我在C ++中已经阅读了variadic templates,但在Java中找不到类似的东西。有这样的东西吗?如果不是,那么模拟相同数据模型的最简洁方法是什么?

3 个答案:

答案 0 :(得分:4)

  

有这样的可用吗?我读过有关可变参数模板的内容   在C ++中,但在Java中找不到类似的东西。有没有这样的事情   可用?

不,这个功能在Java中不可用。

答案 1 :(得分:2)

不,没有直接可用的东西。但是,如果您使用具有Tuple类的库,则可以通过创建接口来模拟它

interface Foo<T> {
    void invoke(T t);
}

(此界面与Consumer<T>基本相同。)

然后你可以做例如

Foo<Tuple<String, Integer, Date, Long>> foo = new Foo<>() {
    ...
}

每个参数数量都需要单独的Tuple类型。如果您有4个参数的Tuple类,但不是5个参数,则可以使用Pair类来挤压额外的参数。

Foo<Tuple<String, Integer, Date, Pair<Long, BigDecimal>>> foo = ...

通过以这种方式嵌套元组类型,您可以获得无限数量的参数。但是,这些变通办法非常难看,我也不会使用它们。

答案 2 :(得分:2)

根据您提供的上下文,我建议您使用List作为参数。如果这些参数有共同点,您可以将列表限制为<T extends CommonParrent>,而不是使用List<Object>。如果没有,您可能仍然想使用标记界面。

这是一个例子。

public class Main {

    public static void main(String[] args) {
        delegate(asList(new ChildOne(1), new ChildTwo(5), new ChildOne(15)));
    }

    private static <T extends Parent> void delegate(List<T> list) {
        list.forEach(item -> {
            switch (item.type) {
                case ONE: delegateOne((ChildOne) item); break;
                case TWO: delegateTwo((ChildTwo) item); break;
                default: throw new UnsupportedOperationException("Type not supported: " + item.type);
            }
        });
    }

    private static void delegateOne(ChildOne childOne) {
        System.out.println("child one: x=" + childOne.x);
    }

    private static void delegateTwo(ChildTwo childTwo) {
        System.out.println("child two: abc=" + childTwo.abc);
    }

}

public class Parent {
    public final Type type;

    public Parent(Type type) {
        this.type = type;
    }
}

public enum Type {
    ONE, TWO
}

public class ChildOne extends Parent {
    public final int x;

    public ChildOne(int x) {
        super(Type.ONE);
        this.x = x;
    }
}

public class ChildTwo extends Parent {
    public final int abc;

    public ChildTwo(int abc) {
        super(Type.TWO);
        this.abc = abc;
    }
}

这个解决方案的最大缺陷是,孩子必须通过enum指定他们的类型,这应该与switch语句中的强制转换相对应,所以每当你改变这两个地方中的一个时,你将不得不记得改变另一个,因为编译器不会告诉你这个。您只能通过运行代码并执行特定分支来找到这样的错误,因此建议使用测试驱动开发。