我不明白为什么我可以返回实现接口的对象,但是编译器在尝试将该对象存储在这种类型的变量中时抱怨。
简单的界面:
public interface ITest {
}
现在,一个简单的类实现了该接口:
public class Test implements ITest {
}
好的,所以我的理解是:Test
是 ITest
现在是问题:
public class Tester {
public static void parameterTest(ITest test) {
}
public static ITest returnValueTest() {
return new Test(); // no compiler error here
}
public static void main(String[] args) {
Test test = new Test();
Tester.parameterTest(test);
test = Tester.returnValueTest(); // compiler complains here
}
}
变量test
来自类型Test
,因此是ITest
。我可以毫无抱怨地将其传递给Tester.parameterTest(ITest test)
。
但是尝试从Tester.returnValueTest()
检索值并将其放入变量test
失败
Incompatible types: ITest cannot be converted to Test
尽管该方法返回Test
对象,但编译器不会抱怨。
为什么呢? 为什么我可以返回一个Test
对象并与方法的返回类型ITest
保持一致,但是不能将此返回的对象放入类型为Test
的变量中? >
答案 0 :(得分:2)
您没有返回Test
对象,而是返回了ITest
实例。
所有Test
对象都实现ITest
,但并非所有ITest
实例都必须是Test
对象。
答案 1 :(得分:0)
对此做一个彻底的了解:我的误解是,我认为对象的继承是“较小的对象适合较大的对象”的问题,但这是错误的思维方式。
对象与接口有关。假设我们有一个 EffectsModule.forFeature([UsersEffects])
类,可以Lifeform
,并说我们有一个grow()
类,它是一个Dog
,可以Lifeform
。以某种方式返回bark()
到Lifeform
的情况下,但并非在每种情况下都满足Dog
的规范,因为并非每个Dog
都可以Lifeform
。由于“变量类型”的含义无非是“确保所包含的对象实现该类型所指定的接口”,因此将bark()
不是Lifeform
放入类型{ {1}}将违反此保证。
因此,在这种情况下-如果方法通过签名返回Dog
,则不能将其放入类型Dog
的变量中,因为它不一定是Lifeform
能够{{ 1}}。您可以通过强制转换确保编译器返回的对象是Dog
,这样就不会抱怨。换句话说,通过强制转换,您可以告诉编译器他“可以保证返回的Dog
是可以bark()
的{{1}}”。
因此,在我的特殊情况下,我可以返回一个Dog
,因为它实现了接口Lifeform
,并且每个人都可以确定,返回的对象将遵循Dog
的规范,因此编译器不抱怨。但是除非将编译器确信该对象确实实现了bark()
提供的接口,否则尝试将对象存储在类型为Test
的变量中会失败。所以我们必须抛弃它,所有的都是彩虹和独角兽。
ITest
但是我们应该小心一点,因为它比仅使用正确类型的变量更容易出错。