我正在检查一些专业编写的代码,并发现了这个片段。 (我希望这个片段足以回答我的问题 - 如果不让我知道的话)
...yada yada yada ....
private ITypedElement format(final ITypedElement elementToFormat) {
try {
if (elementToFormat instanceof IStreamContentAccessor) {
final IStreamContentAccessor resNode = (IStreamContentAccessor) elementToFormat;
final InputStream contentIs = resNode.getContents();
final String contentsString = fromInputStreamToString(contentIs);
final Map options = JavaCore.getOptions();
.... etc....
if
段仅在elementToFormat
是IStreamContentAccessor
的实例时才会运行。那么为什么程序在if
语句“final IStreamContentAccessor resNode = (IStreamContentAccessor)elementToFormat;"
?
什么可能是将某些东西投射到它必须已经存在的类型?
答案 0 :(得分:5)
程序员可能知道它是IStreamContentAccessor
,但没有强制转换,编译器不知道它是IStreamContentAccessor
,所以它不会让程序员访问任何字段/方法特定于IStreamContentAccessor
类。
class ClassA {
Object field1;
}
class ClassB extends ClassA
Object field2;
}
ClassA obj = new ClassB();
obj.field1; // This is fine, the compiler knows it's a ClassA
obj.field2; // This isn't allowed - as far as the compiler knows it's a ClassA, not a ClassB
((ClassB)obj).field2; // This is allowed - now the compiler knows it's a ClassB
答案 1 :(得分:3)
if
语句保证该对象是该类型的实例。但是,对于JVM,对象仍为ITypedElement
类型。只是因为你现在知道它有效并不意味着JVM知道。
演员阵容允许您访问IStreamContentAccessor
的方法。您会注意到,如果您没有演员,如果仅使用elementToFormat
除了ITypedElement
之外没有IStreamContentAccessor
的方法引用Animal a;
a = new Dog();
// "a" contains a Dog in memory, but we only KNOW that it's an Animal
// because that is its declared type
a.bark(); // fails at compile time - not all Animals can bark
Dog d = (Dog) a;
// This is a valid cast, because Dog extends Animal, but it's potentially unsafe.
//
// Another "valid" cast is:
// Cat c = (Cat) a
// but this would fail at runtime (ClassCastException) because the actual
// object in memory (a Dog) cannot be cast to a Cat.
if (a instanceof Dog) {
// Now we KNOW that it's a Dog and we can cast safely.
Dog d2 = (Dog) a;
d2.bark(); // this is valid because d2's declared type is Dog
}
,您就会收到错误。
例如:
if
总而言之,
答案 2 :(得分:1)
这很烦人,但是Java语言需要它。
变量elementToFormat的类型为ITypedElement。要将它用作IStreamContentAccessor需要强制转换。
在这种特定情况下,我们可以看到local参数必须是强制转换类型。但是,赋值的右侧可能不是局部参数 - 例如,成员变量或函数调用。相同的类型检查规则始终适用于右侧值,无论它来自何处。
这个习惯用法很烦人,因为我们必须重复三次。这对我们来说意味着额外的工作。但是 - 由于向下转化有时会产生代码味道 - 我们可以认为这个成语是一个小的语法盐。
答案 3 :(得分:0)
此final IStreamContentAccessor resNode = (IStreamContentAccessor) elementToFormat;
是因为elementToFormat
不属于IStreamContentAccessor
类型,但可以安全地投入其中。
答案 4 :(得分:0)
考虑下面的接口和类:
interface ITypedElement
{
//...
}
interface IStreamContentAccessor
{
InputStream getContents();
}
class Demo implements ITypedElement, IStreamContentAccessor
{
//
}
演示类实现了这两个类,可以发送为:
ITypedElement demoInstance = new Demo();
format(demoInstance);
现在demoInstance
也可以用作IStreamContentAccessor
的实例。
编辑1:
好的,让我们说Demo课可以行为,如ITypedElement
和IStreamContentAccessor
。如果我们创建一个Demo类的实例,它可以显示两个接口的行为,并且可以创建一个指向该实例的变量,使其仅提取我们感兴趣的行为。
Demo d = new Demo();
//d is an instance that can perform everything that `Demo` class is supposed to perform which includes behaviour of the two interfaces as well.
ITypedElement iti = (ITypedElement)d;
// Is above valid? Yes, because Demo implements ITypedElement.
// and we just extracted the `ITypedElement` *behaviour* from `d`.
//similarly
IStreamContentAccessor isa = (IStreamContentAccessor)d;
// Is above valid? Yes, because Demo implements IStreamContentAccessor.
// and we just extracted the `IStreamContentAccessor` *behaviour* from `d`.
//Can we do something like
IStreamContentAccessor isaTough = (IStreamContentAccessor)iti;
// Yes, of course, and this brings up something rather interesting
// Even if we create a variable (`iti`) that *points* to an instance `d`
// it doesn't lose its original nature, rather we only see the behaviour
// we are interested in i.e `ITypedElement`.
基本上iti
,isa
,d
和isaTough
都受到合同设计强加给他们的行为所限制,即:{{1分别是{},ITypedElement
,IStreamContentAccessor
和Demo
。
我认为我只是让它变得有点复杂,而其他人可能会更好地解释一下?