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

13
我希望创建一个特定类型的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个回答

7

有类似的东西吗?我在C++中读到了可变参数模板,但是在Java中找不到类似的东西。有这样的东西吗?

很抱歉,这个特性在Java中不可用。


3
没有直接可用的类似功能。不过,如果您使用具有“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 = ...

通过这种方式嵌套元组类型,您可以获得无限数量的参数。然而,这些变通方法实在太丑陋了,我不会使用它们。

这样说吧:Pair<S,T> 就足够了。但是由于没有人想要一个 Pair<Integer,Pair<String,Pair<Byte,Pair<Float, Long>>>> 这样的东西,所以通常会用不同的方法来解决这个问题。要么放弃类型安全,要么使用像 http://www.javatuples.org/ 这样的库。 - Marco13

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;
    }
}

这个解决方案最大的缺陷是,孩子们必须通过枚举来指定他们的类型,这应该对应于switch语句中的强制转换。因此,每当您更改这两个地方之一时,都需要记住更改另一个地方,因为编译器不会告诉您。您只能通过运行代码并执行特定分支来发现这样的错误,因此建议使用测试驱动开发。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接