不同interface
类型的两个变量之间的difference
是什么,但实际上用same object
实例化。
例如,类 A 实现两个接口 I1 I2。
interface I1 {}
interface I2 {}
class A implements I1, I2 {
...
}
然后,我将类 A 的实例强制转换为接口类型 I1,并将另一个 A 转换为类型 I2
I1 a1 = new A();
I2 a2 = new A();
a1
和a2
有什么区别?类型I1
a1
将无法调用声明接口的方法I2?
a1
和a2
是不同的对象。
例如:
interface I1 {
public void derp();
}
interface I2 {
public void herp();
}
而你有
I1 a1 = new A();
I2 a2 = new A();
a1
是指类实现I1
因此a1
只能调用I1
中定义的方法,该方法derp()
。它不能调用derp()
,因为derp()
是在I2
中定义的。出于同样的原因,a2
只能打电话给herp()
,而不能打电话derp()
。
注意:虽然a1
和a2
是不同的对象,但如果class A
实现I1
和I2
中的所有方法,那么a1
和a2
可以执行相同的操作,它们就不会有区别。 但它们仍然是两个不同的对象
a1
和a2
都指A
类型的对象。 区分变量的"声明类型"和它引用的对象的实际类型(如果变量不为 null(非常重要。
当您声明时
I1 a1 = <anything>;
或者只是
I1 a1;
编译器唯一知道的关于a1
是它必须引用实现I1
的某个对象。 因此,只有在为接口I1
(或超接口或Object
(声明方法时,才能调用方法a1.method(...)
。 此外,a1
只能分配给声明为I1
的另一个变量(或超接口或Object
(,并且如果您将其用作参数
x.someOtherMethod(a1);
仅当参数的类型为I1
、 超接口或Object
时,它才是合法的。
请注意,将其初始化为new A()
并没有什么区别。 出于"允许编译器了解变量的信息"的目的,不考虑初始表达式。 (您可以使用将a1
分配给不同类型的对象的代码。 但即使变量final
,也适用相同的规则。
但是,您可以通过强制转换让编译器将其视为另一种类型。 将接口变量强制转换为任何其他接口始终是合法的,因为某个类在某个地方始终有可能实现这两个接口。 因此,这是合法的:
I2 x = (I2)a1;
在运行时,编译器将检查a1
是否引用除了I1
之外还实现I2
的对象。 如果是这样,则演员表成功。 否则,将引发异常。 假设没有例外,(I2)a1
现在可以以任何其他I2
的任何方式使用。 因此,如果I2
定义了一个方法methodOfI2
,你可以说
((I2)a1).methodOfI2(...parameters...)
是的,你得到了答案。就像你说的,你只能在 a1 上调用 I1 中定义的方法,并且只能调用 I2 中为 a2 定义的方法。
用一个具体的例子来考虑它:
public class PetDog implements FeedableAnimal, PettableAnimal {
...
}
...
FeedableAnimal dog = new PetDog();
现在,如果我将 PetDog 实例化为 FeedableAnimal,我就无法调用 PettableAnimal 中定义的任何方法。那是因为PetDog现在的行为就像可喂食的动物。我们无法知道PetDog是Pettable的,因为我们没有将其实例化为PettableAnimal。
术语澄清:我们不会将宠物狗"投射"为可喂食动物。我们只是说,在编译时,狗的行为就像一个可喂食的动物。在运行时,dog 仍然采用 PetDog 中定义的行为。