【问题标题】:Java Generics, Tightly Bounded Parameter TypeJava 泛型,严格限制的参数类型
【发布时间】: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&lt;T&gt; clazz, T expected, T actual) 但这会迫使程序员明确提及允许的最高类型,当我希望它由语言推断时。

请注意,更接近的解决方案不能简单地重载,因为它们的擦除是相同的。

我希望我已经提供了足够的信息来表达我想要的。我意识到这在 Java 中可能是不可能的,但我希望它是可行的。这也是我在这个论坛上的第一个问题,所以如果我在不知不觉中违反了任何规则,我提前道歉并感谢您的耐心等待!

【问题讨论】:

  • 不,不可能; T 始终可以是 Object
  • 我很确定您所要求的是不可能的,除非创建两个具有不同名称的方法。出于好奇,为什么订单无关紧要要求很重要?你的用例是什么?
  • 我在使用 Map 进行单元测试时遇到了这个问题。我将这些值拉出来,并将它们与作为测试的一部分存储的常量进行比较。有时情况会发生变化,我可以节省数十分钟不运行有时会失败的测试。
  • 你不能像这样实现编译时检查,运行时应该可以使用反射。但是,如果您这样做是为了解决偶尔失败的测试,我不确定这是否是正确的方法。您究竟想在这里解决什么问题?
  • 即使没有擦除,你仍然需要定义两个方法。 T extends S, S extends T 的想法在类型之间创建了循环依赖。显然,除非S == T,否则这两个约束不能同时成立。在 C# 中,您可以通过重载方法来做到这一点(因为没有擦除)。在Java中,根本做不到。

标签: java generics templating static-typing


【解决方案1】:

评论太长了。

从编译器的角度来看,一个可能为假的约束根本不是一个约束,并且不会帮助它确定在各种参数槽中应该允许什么类型,或者允许你做什么他们。因此,该语言(顺便说一句,既不是 C# 也不是 Java)没有语法来定义事物。允许类型约束的原因是它允许您将变量视为方法体中的类型。因此:

public static <T extends Collection> void foo(T a) {
    System.out.println(a.size());
}

将编译并运行,因为所有Collection 子类都有一个size() 方法。问题在于&lt;T extends S || S extends T&gt;(或任何其他编造的语法)没有帮助

例如,假设我们有这个:

public static <T extends List || S extends ArrayList> S bar(T a, S b) {
    // details
}

在这个例子中,我们可以打电话给b.removeRange(...)吗?我们不知道因为S可能不是ArrayLista.size() 怎么样?同样,我们不知道,因为T 可能不是List。所以这没有比我们刚才说的更好的定义了

public static <T, S> S bar(T a, S b) {...}

添加它们可能彼此派生只是为该示例增加了额外的复杂性。

【讨论】:

    猜你喜欢
    • 2021-06-27
    • 1970-01-01
    • 2017-11-17
    • 1970-01-01
    • 2012-08-15
    • 2017-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多