为什么这个类编译即使它没有正确实现其接口?

Pau*_*rds 13 java generics

一个List然后为什么代码(下面)编译?当然MyClass2应该回归List<Integer>

public class Main {
  public static void main(final String[] args) {
    MyClass myClass = new MyClass();
    List list = myClass.getList();
    System.out.println(list);
    System.out.println(list.get(0).getClass());

    MyClass2 myClass2 = new MyClass2();
    List list2 = myClass2.getList();
    System.out.println(list2);
    System.out.println(list2.get(0).getClass());
  }

  public interface Int1 {
    public List getList();
  }

  public interface Int2 extends Int1 {
    @Override
    public List<Integer> getList();
  }

  public static class MyClass implements Int2 {
    @Override
    public List<Integer> getList() {
      return Arrays.asList(1, 2, 3);
    }
  }

  public static class MyClass2 implements Int2 {
    @Override
    public List getList() {
      return Arrays.asList("One", "Two", "Three");
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我注意到如果你试图使它成为一个List<String>然后你得到一个错误"java:Main.MyClass2不是抽象的并且不会覆盖Main.Int2中的抽象方法getList()".我不太明白为什么你在上面的例子中没有得到这个.

注意:我的项目中的问题的解决方案是使接口本身通用,即Int1<X>(当然我使用比这更好的名称,它只是一个例子).

Roh*_*ain 7

我怀疑,编译器应该为您提供Unchecked转换的警告,而不是将其标记为编译器错误.让我们理解为什么它会警告你:

您有以下两种方法来实现以满足您实现的接口的合同:

public List getList();
public List<Integer> getList();
Run Code Online (Sandbox Code Playgroud)

现在,如果在您的类中,您只提供第一个方法的实现,它可以处理第二个方法的请求.您可以返回a List<Integer>返回类型List.那是因为a List<Integer>只是List在运行时,由于类型擦除.

但是,如果你只是给第二个方法实现,它将不满足第一个方法的合同.第一种方法说,它可以返回任何类型List,因为它在返回类型中使用了原始类型.因此,它可以返回List<Integer>,List<Object>,List<String>,任何东西.但第二种方法只能返回List<Integer>.

编译器会在编译时执行此类型检查,它会向您发出警告,List需要进行未经检查的转换List<Integer>,因为由于类型擦除,转换无论如何都会在运行时成功.


这是类似的情况如下:

List<String> listString = new ArrayList<String>();
List rawList = new ArrayList();

listString = rawList;  // Warning: Unchecked conversion
rawList = listString;
Run Code Online (Sandbox Code Playgroud)

推荐阅读:


And*_*niy 5

答案在JLS 7 5.5.1中.参考类型铸造:

给定编译时引用类型S(源)和编译时引用类型T(目标),如果由于以下规则而没有发生编译时错误,则从S到T存在转换转换.

如果S是类类型:

If T is a class type, then either |S| <: |T|, or |T| <: |S|. Otherwise, a compile-time error occurs.

Furthermore, if there exists a supertype X of T, and a supertype Y of S, such that both X and Y are provably distinct parameterized types
Run Code Online (Sandbox Code Playgroud)

(§4.5),并且X和Y的擦除相同,发生编译时错误.

在你的情况下List<Integer>,List<String>可证明是不同的参数化类型,它们都有相同的删除:List.