Java 为什么这个类即使没有正确实现其接口也要编译?
那么下面的代码为什么要编译呢?当然Java 为什么这个类即使没有正确实现其接口也要编译?,java,generics,Java,Generics,那么下面的代码为什么要编译呢?当然MyClass2应该返回一个列表 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
应该返回一个列表
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");
}
}
}
公共类主{
公共静态void main(最终字符串[]args){
MyClass MyClass=新的MyClass();
List=myClass.getList();
系统输出打印项次(列表);
System.out.println(list.get(0.getClass());
MyClass2 MyClass2=新的MyClass2();
List list2=myClass2.getList();
System.out.println(列表2);
System.out.println(list2.get(0.getClass());
}
公共接口Int1{
公共列表getList();
}
公共接口Int2扩展了Int1{
@凌驾
公共列表getList();
}
公共静态类MyClass实现Int2{
@凌驾
公共列表getList(){
返回数组.asList(1,2,3);
}
}
公共静态类MyClass2实现Int2{
@凌驾
公共列表getList(){
返回数组。asList(“一”、“二”、“三”);
}
}
}
我注意到,如果您试图将其设置为列表
,则会出现一个错误“java:Main.MyClass2不是抽象的,并且不会覆盖Main.Int2中的抽象方法getList()。我不太明白为什么在上面的例子中你没有得到这个
注意:在我的项目中,问题的解决方案是使接口本身具有通用性,即
Int1
(当然,我使用了比这个更好的名称,这只是一个示例) Int2扩展Int1,然后列表就可以了
List<String>
根据Java规范,类型会被删除。我想,编译器应该警告您未经检查的转换,而不是将其标记为编译器错误。让我们了解为什么它会警告您: 为了满足所实现接口的契约,您需要实现以下两种方法:
public List getList();
public List<Integer> getList();
建议阅读:
公共列表getList()
的签名与公共列表getList()
的签名相同。对于重写方法,您需要重写方法是被重写方法的子签名。这里的编译器将决定,如果在类型擦除之后它们是相同的,那么子类方法将重写接口方法,并且我们永远不会有冲突 答案是:
给定编译时引用类型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
如果T是一个类类型,那么| S |这两种类型中的任何一种都不会因为类型擦除而产生影响:
public interface Int1 {
public List getList();
}
public interface Int2 extends Int1 {
@Override
public List<Integer> getList();
}
因此,它看起来与类型擦除有关,它是一种生成警告而不是编译器错误的东西。我想这就像我以前见过的其他未经检查的转换场景一样。感谢大家精心研究的答案。您的编译器输出中通常应该有警告,因为Java泛型很糟糕。我不明白我们是如何“满足两个接口契约”的。一个接口覆盖另一个接口,所以肯定是Int2
哪个MyClass2
必须满足?对列表的请求如何处理对列表的请求?我知道在类型擦除之后它们是相同的,但在编译之前它们是不同的,因为在后者中,它会检查您添加到其中/从中删除的内容的类型,等等。@PaulRichards。是的,实际上,从技术上讲,您只实现了一个接口。它扩展了第一个接口。所以,你可以说你只需要满足单一接口的契约。正如我所说,返回类型为List
的方法可以返回任何列表类型。因此,它还可以返回列表
。这就是另一种方法的意义所在。它应该返回List
,这由List
负责。是的,它们在编译时是不同的。这就是为什么编译器会给您未检查的转换警告。因为它不确定两个列表是否相同。
List<String> listString = new ArrayList<String>();
List rawList = new ArrayList();
listString = rawList; // Warning: Unchecked conversion
rawList = listString;
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
public interface Int1 {
public List getList();
}
public interface Int2 extends Int1 {
@Override
public List<Integer> getList();
}
java: Note: Main.java uses unchecked or unsafe operations.
java: Note: Recompile with -Xlint:unchecked for details.