Java泛型二义性方法

标签 java generics

我无法理解以下代码背后的行为。任何有助于理解的帮助将不胜感激。

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/

相关文章:

java - 在 Spring 中,您可以使用 BeanDefinitionDecorator 更改属性占位符值吗?

java - Kotlin Mockito 总是返回作为参数传递的对象

java - 在 Java 中使用 Jackson 进行 map 反序列化

c# - ArrayList 与 C# 中的 List<>

c# - 如何推断对象的类型并在构造期间在泛型参数中使用该类型

java - 在 Java 中定义泛型方法的最佳方式是什么?

java - 在 MultipleOutputs 中 - 避免将我的 key 写入文件

java - 如何在使用 JUnit、Spring Boot 和 TestContainers 的集成测试中防止数据冲突?

java - spring中@Configuration类的作用域

java - 方法调用和通配符