如何编写一个在java中采用相同类型的两个参数的generics方法?
当我注意到以下代码在没有警告的情况下编译并打印出Integer / String
时,我感到非常惊讶:
public final class GenericsTest { private static void method(T arg1, T arg2) { System.out.println(arg1.getClass().getSimpleName()); System.out.println(arg2.getClass().getSimpleName()); } public static void main(String[] args) { method(1, "1"); } }
我预计会出现编译错误。
这段代码编译的原因是什么?
确保参数具有相同类型的正确方法是什么?
编辑:有界类型参数怎么样? 我能想到的最好的是:
private static void method(T arg1, U arg2) { System.out.println(arg1.getClass().getSimpleName()); System.out.println(arg2.getClass().getSimpleName()); }
不幸的是,java不允许循环约束。 不编译。 这是死路一条吗?
这个编译的原因是因为Java会推断传入的参数的最具体的超类型,在这种情况下, Object
Serializable & Comparable extends Serializable & Comparable extends Comparable>>>
Serializable & Comparable extends Serializable & Comparable extends Comparable>>>
Serializable & Comparable extends Serializable & Comparable extends Comparable>>>
,将1
装入Integer
,将"1"
作为String
传递。
没有generics:
private static void method(Number arg1, Number arg2) {
即使没有generics,你也可以传入一个Integer
和一个Double
。
只有当问题类型是final
类型时,才能执行此操作,无需generics:
private static void method(String arg1, String arg2) { // Yes, they're both Strings, guaranteed.
我可以想到有一个带有generics的边缘情况,以确保它们是确切的类型。 如果你有一个final
类,并且你设置了一个上限,那么你可以将它限制在同一个类。
public void method(T arg1, T arg2) { // Yes, they're both MyFinalClasses }
但是,如果没有generics,你可以做同样的事情。
public void method(MyFinalClass arg1, MyFinalClass arg2) { // Yes, they're both MyFinalClasses }
您可以将该类添加为附加参数。
private static void method(T arg1, T arg2, Class type) { // ... }
现在您必须指定常见类型。
你仍然可以调用method(1, "1", Object.class);
但至少你是明确的共同类型。
这是不可能的。 或者换一种方式来看,两个引用参数始终是“相同类型” – Object
– 引用类型的任何参数始终是Object
实例。
T
始终可以是Object
,并且可以使用任意两个引用参数。 即使使用
, T
和U
都可以是Object
,因此再次获取任意两个参数。
造成这种情况的根本原因是没有类型安全原因要求这样的约束。 inheritance的一个主要观点是,应该可以安全地处理子类实例,如超类实例。 超类类型的引用类型可以自由地指向该类或子类的实例。 因此,具有相同编译时类型的两个引用变量始终可以完全安全地在运行时指向不同子类类型的实例。 因此,在编译时,您永远不能对两个实例的实际运行时类之间的关系做出任何声明,而不是它们是编译时类型的子类。 由于两个参数在运行时是不同类的实例是安全的,因此实际传递不同编译时类型的两个参数也同样安全。