尝试将对象存储在非常类型的变量中时,类型不兼容

时间:2019-10-13 21:50:05

标签: java

我不明白为什么我可以返回实现接口的对象,但是编译器在尝试将该对象存储在这种类型的变量中时抱怨。

简单的界面:

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的变量中? >

2 个答案:

答案 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

但是我们应该小心一点,因为它比仅使用正确类型的变量更容易出错。