[英]How to write a generic method that takes two arguments of the same types in java?
当我注意到以下代码编译时没有警告并打印Integer / String
时,我感到非常惊讶:
public final class GenericsTest {
private static <T> 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 <T, U extends T> void method(T arg1, U arg2) {
System.out.println(arg1.getClass().getSimpleName());
System.out.println(arg2.getClass().getSimpleName());
}
不幸的是,java 不允许循环约束。 <T extends U, U extends T>
不能编译。 这是一个死胡同吗?
这个编译的原因是因为 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
传递之后。
没有泛型:
private static void method(Number arg1, Number arg2) {
即使没有泛型,您也可以传入一个Integer
和一个Double
。
只有当有问题的类型是final
时,你才能做到这一点,没有泛型:
private static void method(String arg1, String arg2) {
// Yes, they're both Strings, guaranteed.
我可以想到一种泛型的边缘情况,以确保它们是确切的类型。 如果你有一个final
类,并且你设置了一个上限,那么你可以将它限制在同一个类中。
public <T extends MyFinalClass> void method(T arg1, T arg2) {
// Yes, they're both MyFinalClasses
}
但是你可以在没有泛型的情况下做同样的事情。
public void method(MyFinalClass arg1, MyFinalClass arg2) {
// Yes, they're both MyFinalClasses
}
您可以将该类添加为附加参数。
private static <T> void method(T arg1, T arg2, Class<T> type) {
// ...
}
现在您必须指定通用类型。
你仍然可以调用method(1, "1", Object.class);
但至少你是明确的公共类型。
这是不可能的。 或者换个角度来看,两个引用参数总是“相同类型”—— Object
任何引用类型的参数总是Object
实例。
T
始终可以是Object
,并采用任意两个引用参数。 即使使用<T, U extends T> void method(T arg1, U arg2)
, T
和U
都可以是Object
,因此再次采用任意两个参数。
这样做的根本原因是没有类型安全的理由来设置这样的约束。 继承的要点之一是应该可以安全地像对待超类实例一样对待子类实例。 超类类型的引用类型可以自由地指向该类或子类的实例。 因此,具有相同编译时类型的两个引用变量始终可以在运行时完全安全地指向不同子类类型的实例。 因此,在编译时,除了它们是编译时类型的子类之外,您永远不能就两个实例的实际运行时类的关系做出任何声明。 由于两个参数在运行时作为不同类的实例是安全的,因此实际传递不同编译时类型的两个参数也同样安全。
这就是我解决这个问题的方法 - 我想创建一个方法来创建两个对象的差异。
public List<Change> getChanges(Object o1, Object o2);
自然地,我希望 o1 和 o2 都属于同一类型。 我通过将此方法封装在参数化类中解决了这个问题。
public class DiffGenerator<T> {
public List<Change> getChanges(T o1, T o2) {
//code
}
}
这可以用作: List<Change> changes = new DiffGenerator<MyClass>().getChanges(myClassOld, myClassNew);
为我工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.