【发布时间】:2013-12-10 18:59:05
【问题描述】:
我希望有一个具有类似签名的方法
method(T1 t1, T2 t2)
使得T2是-一个T1和/或T1是-一个T2。我不希望 T1 和 T2 都是 T 但两者都不是另一个的情况。我希望最允许的类型以继承树中的最高 T1 或 T2 为界。我正在使用 Java 6。
下面是尝试展示一些所需的用例
class Experiment
{
static List genericList = new ArrayList();
static ArrayList arrayList = new ArrayList();
static class Test1 { }
static class Test2 extends Test1 { }
static class Test3 extends Test1 { }
static <T> T experiment0(T expected, T actual)
{
return actual;
}
/** Almost works, but want arbitrary ordering. Cannot overload due to erasure. */
static <T, S extends T> S experiment1(T expected, S actual)
{
return actual;
}
private static void experimentDriver()
{
// good, allowed
List l = experiment0(genericList, arrayList);
// bad, allowed; want compile-time error
Object o = experiment0(new String(), new Integer(0));
// good, allowed
Test1 test1 = experiment1(new Test1(), new Test3());
String string = experiment1(new String(), new String());
List list = experiment1(genericList, new ArrayList());
// good, disallowed
experiment1(new Test2(), new Test3());
experiment1(new Test3(), new Test2());
experiment1(new Integer(0), new String());
experiment1(new ArrayList(), new LinkedList());
// bad, disallowed; want either order
experiment1(new Test3(), new Test1());
experiment1(new ArrayList(), genericList);
}
}
我知道我可以通过类似的签名实现类似的效果
experiment(Class<T> clazz, T expected, T actual)
但这会迫使程序员明确提及允许的最高类型,当我希望它由语言推断时。
请注意,更接近的解决方案不能简单地重载,因为它们的擦除是相同的。
我希望我已经提供了足够的信息来表达我想要的。我意识到这在 Java 中可能是不可能的,但我希望它是可行的。这也是我在这个论坛上的第一个问题,所以如果我在不知不觉中违反了任何规则,我提前道歉并感谢您的耐心等待!
【问题讨论】:
-
不,不可能;
T始终可以是Object。 -
我很确定您所要求的是不可能的,除非创建两个具有不同名称的方法。出于好奇,为什么订单无关紧要要求很重要?你的用例是什么?
-
我在使用 Map
进行单元测试时遇到了这个问题。我将这些值拉出来,并将它们与作为测试的一部分存储的常量进行比较。有时情况会发生变化,我可以节省数十分钟不运行有时会失败的测试。 -
你不能像这样实现编译时检查,运行时应该可以使用反射。但是,如果您这样做是为了解决偶尔失败的测试,我不确定这是否是正确的方法。您究竟想在这里解决什么问题?
-
即使没有擦除,你仍然需要定义两个方法。
T extends S, S extends T的想法在类型之间创建了循环依赖。显然,除非S == T,否则这两个约束不能同时成立。在 C# 中,您可以通过重载方法来做到这一点(因为没有擦除)。在Java中,根本做不到。
标签: java generics templating static-typing