Java泛型,紧密绑定的参数类型

Java泛型,紧密绑定的参数类型,java,generics,templating,static-typing,Java,Generics,Templating,Static Typing,我希望有一个签名如下的方法 方法(T1-T1,T2-T2) 使得T2是T1和/或T1是T2。我不想要T1和T2都是T,但两者都不是-a的情况。我希望最允许的类型在继承树中以T1或T2中的最高值为界。我正在使用Java6 下面试图展示一些期望的用例 class Experiment { static List genericList = new ArrayList(); static ArrayList arrayList = new ArrayList(); static clas

我希望有一个签名如下的方法
方法(T1-T1,T2-T2)
使得T2是T1和/或T1是T2。我不想要T1和T2都是T,但两者都不是-a的情况。我希望最允许的类型在继承树中以T1或T2中的最高值为界。我正在使用Java6

下面试图展示一些期望的用例

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);
  }
}
课堂实验
{
静态列表genericList=新的ArrayList();
静态ArrayList ArrayList=新ArrayList();
静态类Test1{}
静态类Test2扩展了Test1{}
静态类Test3扩展了Test1{}
静态T试验0(预期T,实际T)
{
返回实际值;
}
/**几乎可以工作,但需要任意排序。不能因擦除而过载*/
静态S实验1(预期为T,实际为S)
{
返回实际值;
}
专用静态驱动程序()
{
//好的,允许
列表l=0(genericList,arrayList);
//错误,允许;需要编译时错误
对象o=0(新字符串(),新整数(0));
//好的,允许
Test1 Test1=experiment1(新Test1(),新Test3());
String String=experiment1(新字符串(),新字符串());
List List=experiment1(genericslist,newarraylist());
//好的,不允许
实验1(新Test2(),新Test3());
实验1(新Test3(),新Test2());
实验1(新整数(0),新字符串());
实验1(新建ArrayList(),新建LinkedList());
//不好,不允许;想要任何一个命令吗
实验1(新Test3(),新Test1());
实验1(新ArrayList(),genericList);
}
}
我知道我可以用这样的签名来实现类似的目标
实验(课堂上,T预期,T实际)
但这迫使程序员在我希望由语言推断时显式地提到允许的最高类型

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


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

评论时间太长了

从编译器的角度来看,可能为false的约束根本不是约束,也无助于它确定各种参数槽中应该允许哪些类型,或者允许您对它们执行什么操作。因此,这种语言(顺便说一句,既不是C#也不是Java)没有语法以这种方式定义事物。允许类型约束的原因是,它允许您将变量视为方法体中的类型。因此:

public static <T extends Collection> void foo(T a) {
    System.out.println(a.size());
}
在这个例子中,我们可以调用
b.removeRange(…)
?我们不知道,因为
S
可能不是
ArrayList
。a.size()怎么样?同样,我们不知道,因为
t
可能不是
列表。所以这并没有比我们刚才说的更好的定义

public static <T, S> S bar(T a, S b) {...}
publicstaticsbar(ta,sb){…}

加上它们可能相互派生,只会增加该示例的复杂性。

不,不可能
T
始终可以是
Object
。我很确定,除了创建两个名称不同的方法之外,您所要求的是不可能的。出于好奇,为什么订单与需求无关?您的用例是什么?我在使用Map进行单元测试时遇到了这个问题。我在取出这些值时将其转换,并将它们与作为测试一部分存储的常量进行比较。有时情况会发生变化,我可以节省几十分钟不运行测试,而这些测试有时会失败。您无法实现这样的编译时检查,运行时应该可以使用反射。但是,如果你这样做是为了解决偶尔会失败的测试,我不确定这是不是正确的方法。你到底想解决什么?即使没有擦除,你仍然需要定义两种方法。
T扩展S,S扩展T
的思想在类型之间创建了循环依赖关系。显然,这两个约束不能同时成立,除非
S==t
。在C#中,可以通过重载方法来实现(因为没有擦除)。在Java中,这根本无法完成。
public static <T, S> S bar(T a, S b) {...}