我已经阅读了这篇文章here,并试图弄清楚如何使用绑定类型。我试图实现的是一种处理四种不同情况的参数化方法:
所以这是代码:
public class Main {
public static void main(String... args) {
B b = new B();
D d = new D();
I i = new I() {
};
handle("aaasd");
handle(b);
handle(d); <---- Problem 1
handle(i);
}
public static class B {
}
public static interface I {
}
public static class D extends B implements I {
}
public static <T> void handle(T objT) {
System.out.println("T");
}
private static <T extends B> void handle(T obj) {
System.out.println("B");
}
public static <T extends B & I> void handle(T objT) { <--- Problem 2
System.out.println("B+I");
}
private static <T extends I> void handle(T obj) {
System.out.println("I");
}
}
编译器抱怨并说两件事:
不明确的电话
方法句柄(Main.D)对于Main类型是不明确的 我猜这个问题是由与问题2相同的原因引起的。我明确地将T的类型限制为B和I的子类型,从而消除了我认为的模糊性。
相同的擦除句柄
方法句柄(T)与Main类型中的另一种方法具有相同的擦除句柄(Main.B) 我的猜测是,这是所有问题的真正原因。 Java在运行时以某种方式删除了对我的绑定?但是当我用类型B调用方法时,这并没有调用带注释的方法。
有人可以解释我如何解决问题/区分B,B&amp; I和I?
答案 0 :(得分:1)
Java在运行时以某种方式删除了对我的绑定?
不,Java在运行时删除每个类型信息(除了反射目的),这称为类型擦除。
使用边界编译器可以将代码转换为handle(Object)
,handle(B)
和handle(I)
,但在T extends B & I
情况下编译器会发生冲突。
AFAIK,没有共同的约束,没有办法解决这个问题。 T extends D
代替T extends B & I
D extends B implements I
或更改方法名称或添加其他参数。
另一种方法可能是将B + I情况下的逻辑添加到B或I方法中并检查内部的第二个条件,例如
private static <T extends B> void handle(T obj) {
if( obj instanceof I) {
System.out.println("B+I");
}
else {
System.out.println("B");
}
}
答案 1 :(得分:0)
有一种称为类型擦除的概念适用于Java中的所有泛型。使用泛型方法,在编译之后,字节代码中的方法显示为它们的擦除,所以
public static <T> void handle(T objT) {
System.out.println("T");
}
private static <T extends B> void handle(T obj) {
System.out.println("B");
}
public static <T extends B & I> void handle(T objT) { <--- Problem 2
System.out.println("B+I");
}
private static <T extends I> void handle(T obj) {
System.out.println("I");
}
实际上变成了
public static void handle(Object objT) {
System.out.println("T");
}
private static void handle(B obj) {
System.out.println("B");
}
public static void handle(B objT) {
System.out.println("B+I");
}
private static void handle(I obj) {
System.out.println("I");
}
类型变量的最左边界限是替换为该类型的参数。如您所见,第二种和第三种方法都具有相同的名称和相同的参数类型,即。相同的签名。编译器不允许这样做。
但是,bounds的语法会强制您在任何接口类型之前提供类类型
<T extends I & B>
无效。它也行不通,因为你的第四种方法将再次具有相同的擦除功能。
另外,调用
handle(d);
是一个问题,因为第二个和第四个方法都可以处理它,没有一个更具体。这被称为重载模糊。