Java 未选中强制转换警告:接口作为返回值,存储在实现所述接口的类中

Java 未选中强制转换警告:接口作为返回值,存储在实现所述接口的类中,java,interface,multiple-inheritance,Java,Interface,Multiple Inheritance,我的情况是,我有一个函数 公共静态MyInterface doSomething(){…} 还有一节课 MyList扩展MyListObject实现MyInterface 和: MyObjectA扩展了MyObject MyListObject仅实现接口Collection和List 我现在的问题是,下面的代码 MyList var=(MyList)doSomething() 产生 类型安全:未选中从MyInterface到MyList的强制转换 警告。 为什么会这样?我的意思是doOper

我的情况是,我有一个函数

公共静态MyInterface doSomething(){…}

还有一节课

MyList扩展MyListObject实现MyInterface

和:

  • MyObjectA
    扩展了
    MyObject

  • MyListObject
    仅实现接口
    Collection
    List
我现在的问题是,下面的代码

MyList var=(MyList)doSomething()

产生

类型安全:未选中从MyInterface到MyList的强制转换

警告。
为什么会这样?我的意思是
doOperation()
返回
MyInterface
类型,并
MyList
实现所述接口


我希望我的代码示例解释了所有类和接口之间的完整关系,并且我没有遗漏任何内容。

您假装
MyInterface
MyList
,但我很确定它不是–尽管您没有显示
MyInterface
的实际定义

打个比方,你试图把每一个工具(
MyInterface
)都当作锤子(
MyList

如果您确定
doSomething()
始终返回
MyList
,则可以使用
@SuppressWarnings(“未选中”)注释标记包含强制转换的方法。但是,为什么首先要声明
doSomething()
返回更通用的
MyInterface

interface Flying {
   void fly();
}

class Bird extends Animal implements Flying {
    ...
}

List<Flying> listFlying();

List<Flying> list = listFlying();
否则,安全需要一些铲:

List<Bird> birds = list.stream() // Or listFlying().stream()
    .filter(Bird.class::isInstance)
    .map(Bird.class::cast)
    .collect(Collectors.toList());
List birds=List.stream()//或listfiling().stream()
.filter(Bird.class::isInstance)
.map(Bird.class::cast)
.collect(Collectors.toList());

本质上,强制转换中的类型可能不包含
,除非它是
。(这条规则也有例外,但它们是极端情况,与此无关。)

泛型是一种编译时类型检查机制。在运行时,由于类型擦除,不存在
MyList
类。只有一个
MyList

这意味着编译器只能生成以下代码:

(MyList<?>) doSomething();
(MyList)doSomething();
试图强制编译器假定结果具有特定泛型类型是不安全的,因为执行强制转换的代码无法检查该类型。因此,您的施法是未经检查的施法

执行此操作的安全方法是执行非泛型强制转换:

MyList<MyObjectA> var = new MyList<>();
MyList<?> list = (MyList<?>) doSomething();
for (Object element : list) {
    var.add((MyObjectA) element);
}
MyList var=new MyList();
MyList list=(MyList)doSomething();
for(对象元素:列表){
变量add((MyObjectA)元素);
}

注意:
var
现在是Java中的保留关键字。应避免将其用作变量名。

虽然
doOperation()
返回
MyInterface
,但不能确定它是否返回
MyList
。你把它当作一个事实来编程,编译器告诉你这是一个不安全的强制转换。如果您返回任何其他内容,它将在运行时失败。这是一个糟糕的构造,从您的部分来说有点令人惊讶的设计选择。
MyInterface
不一定是
MyList
。因为可以有多个类实现
MyInterface
。您调用的方法也只返回
MyInterface
,因此不能保证您可以将结果转换为
MyList
,谢谢大家的有益解释。现在我真正理解了这个问题。我之所以选择“var”,是因为在键入时我想不出任何变量名。你的回答帮助我解决了这个问题,非常感谢@Chayze如果您觉得此答案充分解决了您的问题,请单击答案旁边的复选标记,自由选择。
MyList<MyObjectA> var = new MyList<>();
MyList<?> list = (MyList<?>) doSomething();
for (Object element : list) {
    var.add((MyObjectA) element);
}