3

我正在检查一些专业编写的代码,并遇到了这个片段。(我希望这个片段足以回答我的问题 - 如果不让我知道)

...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;"

将某些东西转换为它必须已经是的类型可能有什么意义?

4

5 回答 5

5

程序员可能知道它是 a IStreamContentAccessor,但没有强制转换编译器不知道它是 a 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
于 2013-05-08T20:27:34.657 回答
3

if语句保证对象是该类型的实例。但是,对于 JVM,对象仍然是ITypedElement. 仅仅因为现在知道它是有效的并不意味着 JVM 知道。

强制转换允许您访问IStreamContentAccessor. 你会注意到,如果没有强制转换,如果你只引用没有但有的elementToFormat方法,你会得到一个错误。ITypedElementIStreamContentAccessor

例如:

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语句确保强制转换是有效的
  • 这两个语句在技术上是完全独立的
  • 你比JRE聪明
于 2013-05-08T20:27:54.710 回答
1

这很烦人,但 Java 语言要求这样做。

变量 elementToFormat 的类型为 ITypedElement。要将其用作 IStreamContentAccessor 需要强制转换。

在这种特定情况下,我们可以看到本地参数必须是强制转换类型。但是,赋值的右侧可能不是局部参数——例如,成员变量或函数调用。相同的类型检查规则始终适用于右侧值,无论它来自何处。

这个成语很烦人,因为我们必须重复输入 3 次。这对我们来说意味着一些额外的工作。但是——因为向下转换有时是一种代码味道——我们可以认为这个习语是一种句法盐。

于 2013-05-08T20:28:02.527 回答
0

考虑下面的接口和类:

interface ITypedElement
{
    //...
}

interface IStreamContentAccessor
{
    InputStream getContents();
}

class Demo implements ITypedElement, IStreamContentAccessor
{
    //
}

演示类实现了这两个类,可以发送为:

ITypedElement demoInstance = new Demo();

format(demoInstance);

现在demoInstance也可以使用.IStreamContentAccessor

编辑1:

好的,让我们说 Demo 类可以表现得像ITypedElementIStreamContentAccessor。如果我们创建一个 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`.

本质itiisadisaTough都是相同的东西,它们分别受到合同设计强加给他们的行为的限制,即:ITypedElement、和。IStreamContentAccessorDemoIStreamContentAccessor

我想我只是让它比它应该的复杂一点,prolly其他人可能会解释得更好吗?

于 2013-05-08T20:37:06.763 回答
0

final IStreamContentAccessor resNode = (IStreamContentAccessor) elementToFormat;是因为elementToFormat它不是类型IStreamContentAccessor,但可以安全地投入其中。

于 2013-05-08T20:27:56.480 回答