我无法理解以下代码背后的行为。任何有助于理解的帮助将不胜感激。
class Binder {
<T> void bind(Class<T> clazz, Type<T> type) {
System.out.println("clazz type");
}
<T> void bind(T obj, Type<T> type) {
System.out.println("obj type");
}
}
class Type<T> {
Type(T obj) { }
}
Binder binder = new Binder();
binder.bind(String.class, new Type<String>("x")) //works
binder.bind(Object.class, new Type<Object>(new Object())) //ambiguous
上面的代码将失败
ERROR: reference to bind is ambiguous
both method <T>bind(java.lang.Class<T>,Type<T>) in Binder and method <T>bind(T,Type<T>) in Binder match
如果我要删除每个方法的第二个参数,两个绑定(bind)调用都会执行第一个方法
class Binder {
<T> void bind(Class<T> clazz) {
System.out.println("clazz");
}
<T> void bind(T obj) {
System.out.println("obj");
}
}
Binder binder = new Binder();
binder.bind(String.class)
binder.bind(Object.class)
以上将打印“clazz”两次。
最佳答案
为了我的理解,让我修改系统输出:
public class Binder
{
class Type<T>
{
Type( T obj )
{
System.out.println( "Type class: " + obj.getClass( ) );
}
}
}
我们可以对每个案例一一进行测试:
对象调用如何模棱两可?
1)对类的测试对象调用:
<T> void bind( Class<T> clazz, Type<T> type )
{
System.out.println( "test clazz bind" );
System.out.println( "Clazz class: " + clazz );
}
@Test
public void bind_Object( )
{
Binder binder = new Binder( );
binder.bind(Object.class, new Type<Object>(new Object());
}
输出:
Type class: class java.lang.Object
test clazz bind
Clazz class: class java.lang.Object
我的解释:
在这种情况下,T 被选为对象。所以函数声明变成了
bind(Class<Object> obj, Type<Object>)
这很好,因为我们正在调用bind(Object.class, new Type<Object)
在哪里 Object.class is assignable to Class<Object>
所以这个电话很好。2) T 上的测试对象调用:
<T> void bind( T obj, Type<T> type )
{
System.out.println( "test obj bind" );
System.out.println( "Obj class: " + obj.getClass() );
}
@Test
public void bind_Object( )
{
Binder binder = new Binder( );
binder.bind(Object.class, new Type<Object>(new Object());
}
输出:
Type class: class java.lang.Object
test obj bind
Obj class: class java.lang.Class
我的解释:
在这种情况下,T 被选为对象。所以函数声明变成了
bind(Object obj, Type<Object>)
这很好,因为我们用 bind(Object.class, new Type<Object), Class<Object>
调用可分配给 Object
作为第一个参数。所以这两种方法都适用于 Object 调用。但是为什么 String 调用没有歧义呢?让我们测试一下:
字符串调用如何不模棱两可?
3)对类的测试字符串调用:
<T> void bind( Class<T> clazz,Type<T> type )
{
System.out.println( "test clazz bind" );
System.out.println( "Clazz class: " + clazz );
}
@Test
public void bind_String( )
{
Binder binder = new Binder( );
binder.bind( String.class, new Type<String>( "x") );
}
输出:
Type class: class java.lang.String
test clazz bind
Clazz class: class java.lang.String
我的解释:
在这种情况下,T 被选为字符串。所以函数声明变成了
bind(Class<String> clazz, Type<String> type)
这很好,因为我们用 bind(String.class, new Type<String)
调用这肯定是可以分配的。 T绑定(bind)怎么样?4) T 上的测试字符串调用:
<T> void bind( T obj, Type<T> type )
{
System.out.println( "test obj bind" );
System.out.println( "Obj class: " + obj.getClass() );
}
@Test
public void bind_String( )
{
Binder binder = new Binder( );
binder.bind( String.class, new Type<String>( "x") );
}
输出:
编译器错误
我的解释:
在这种情况下,T 被选为字符串。所以函数声明变成了
bind(String obj, Type<String> type)
这不好,因为我们用 bind(String.class, new Type<String)
调用. String.class which means Class<String>
.所以我们尝试调用(String, Type<String>)
功能与 (Class, Type<String)
不可分配的输入。
关于Java泛型二义性方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57826825/