为什么在重写模板参数为 <T 扩展接口>的模板方法时返回泛型类有效?



请考虑以下场景:

/**
 * A sample interface.
 */
public interface MyInterface
{
}
/**
 * First sample implementation of the above interface.
 */
public class MyClass1 implements MyInterface
{
    public String toString()
    {
        return "[ My Class 1 ]";
    }
}

/**
 * Second sample implementation of the above interface.
 */
public class MyClass2 implements MyInterface
{
    public String toString()
    {
        return "[ My Class 2 ]";
    }
}

import java.util.Collection;
/**
 * A service interface that declares a generic method
 * returning a collection of subtype the interface defined above.
 */
public interface MyService
{
    public <T> extends MyInterface<Collection<T>> myMethod();
}
import java.util.Arrays;
import java.util.Collection;
/**
 * The implementation of the service interface 
 * that returns the generic type. 
 */
public class MyServiceImpl implements MyService
{
    @Override
    public Collection<MyInterface> myMethod()
    {
        return Arrays.asList(new MyClass1(), new MyClass2());
    }
}
import java.util.Collection;
/**
 * Simple main class to drive the point 
 * I would like raise in the query below.
 */
public class MyMain
{
    public static void main(String[] args)
    {
        MyService service = new MyServiceImpl();
        Collection<MyClass1> list = service.myMethod();
        // This works at runtime.
        System.out.println(list);
        for (MyClass1 obj : list)
        {
            // This throws ClassCastException at runtime.
            System.out.println(obj);
        }
    }
}

在上面的代码中,当MyService声明涉及给定类型的特定子类型时,Java泛型实现如何允许MyServiceImpl的实现返回泛型类?

如果我添加正确的泛型类型

public class MyMain {
    public static void main(String[] args) {
        MyService service = new MyServiceImpl();
        Collection<MyInterface> list = service.myMethod();
        // This works at runtime.
        System.out.println(list);
        for (MyInterface obj : list) {
            // This doesn't throw a ClassCastException
            System.out.println(obj);
        }
    }
}

我得到

[[ My Class 1 ], [ My Class 2 ]]
[ My Class 1 ]
[ My Class 2 ]

我不明白你如何让你的例子在没有警告的情况下编译并触发 ClassCastException。

System.out.println(list);

这一行没问题,因为它只是为在没有泛型类型的情况下强制转换为Object的两个元素调用方法toString()

for (MyClass1 obj : list)
{
   // This throws ClassCastException at runtime.
   System.out.println(obj);
}

但是在这里你会得到一个运行时 ClassCastException,因为你正在将列表中的MyClass2元素强制转换为类MyClass1,这不是MyClass2的超类。for 循环需要遍历公共超类或接口。

最新更新