摘自一本Java书:
在将值存储在变量中时,编译器会检查您是否没有承诺。如果将子类引用分配给超类变量,则将有前途,而编译器将简单地允许您这样做。如果您将超类引用分配给子类变量,您将很有希望。然后,您必须使用强制转换,以便可以在运行时检查承诺。
如果您能向我解释技术问题上的“承诺”,我将理解。我查看了字典,但该词不适合本段内容。
答案 0 :(得分:2)
这不是标准术语,但是作者似乎正在使用它(试图)使初学者可以使用它。 (这并不容易。)基本上,他们是说如果您有:
class Base {
public void baseMethod() {
// ...
}
}
class Derived extends Base {
public void derivedMethod() {
// ...
}
}
您可以这样做:
Base b = new Derived();
...因为Base
类型定义的所有功能(baseMethod
)在您分配的对象(Derived
的实例)上可用。您“承诺”对象b
所指的对象将具有baseMethod
,并且确实如此。
但是您不能这样做:
Derived d = new Base();
...因为Derived
类型定义了您要分配的对象(derivedMethod
实例)所不具备的功能(Base
)。您“承诺”对象d
所指的对象将有derivedMethod
,但没有,所以您“承诺太多”。
发表评论:
在第二个示例中铸造如何出现?
该示例中未涉及。强制转换不会改变对象的含义,而只是改变您对它的引用。¹
但是假设您有这样的事情:
void someMethod(Base obj) {
if (obj instanceof Derived) { // Just an example, `instanceof` is usually
// an anti-pattern
Derived d = (Derived)obj;
// ...
}
}
该方法接收一个对象,并且只有一个Base
引用。但是随后代码检查并发现该对象实际上是Derived
(或Derived
的子类),因此它使用强制转换来更改其具有的引用类型,以便可以使用{{ 1}}功能。铸造就是这样进入的。
同样,请注意,在十分之九的情况下,使用Derived
是一种反模式。在十分之九的情况下,您想重构代码,以便将接口类型传递给仅定义代码所需功能的代码。第十种情况很少见。 :-)
在第二次铸造中铸造是否总是成功?
仅当您确定地确定对象属于您要转换的类型或该类型的子类时,才可以。如果您不确定,则强制转换可能会抛出ClassCastException
。
¹... ...在将图元(例如instanceof
)强制转换为其包装对象(例如int
)的特殊情况下,反之亦然。即使这样,它也不会更改对象,它只是创建一个对象(在转换为包装类型时)或创建一个基元(在转换为原始类型时)。