【问题标题】:Java casting orderJava 转换顺序
【发布时间】:2011-04-23 04:54:43
【问题描述】:

假设我有以下设置

class A {
    B foo();
}

class C extends B {

}

// later
A a = new A();
C theFoo = (C)a.foo();

我们知道a.foo() 返回类型 B。

当我做(C)a.foo()时,是吗

  1. a 转换为C,然后尝试调用foo()
  2. a 上调用foo() 并将结果转换为C 类型?

我发现很难确定,并且总是谨慎地使用额外的括号(这不是一个坏主意,为了可读性,但现在我很好奇)

这是对ObjectInputStream.readObject() 的具体引用,尽管我看不出这会如何改变行为。

【问题讨论】:

  • 一种快速找出方法是在 C.foo 和 B.foo 中设置断点并进行调试。那么无论哪个被击中都会回答你的问题。顺便问下好问题
  • 嗯,不知道 Eclipse 是否会让我在 Java 核心类中设置断点... :-)
  • 您可以在自己引用的库上执行此操作,因此我认为核心库的反应相同。只要您附加了源代码,它就可以让您设置断点(尚未测试它们是否真正触发)

标签: java casting default


【解决方案1】:

(C)a.foo() 等价于(C)(a.foo()),即问题中的#2。

要获得#1,您必须写((C)a).foo()

Java 语言规范没有在一个漂亮、易于阅读的摘要中指定运算符优先级。

Introduction to Programming in Java

Appendix A 由 Sedgewick 和 Wayne 撰写,有一个全面的运算符优先级表。

The Java Programming Language 的附录 B 有一个运算符优先级表,但不如 Sedgewick 的完整。

仔细检查 Java 语言规范中的 grammar 可以确定相关转换和方法调用表达式的相对优先级:

表达式表达式1 [赋值运算符表达式1]] 表达式1: Expression2 [Expression1Rest] 表达式1休息: ?表达式:表达式1 表达式2: Expression3 [Expression2Rest] 表达式2休息: {中缀表达式3} Expression3 instanceof 类型 表达式3: PrefixOp 表达式3 (表达式|类型)表达式3 主要 {选择器} {PostfixOp} 基本的: ParExpression NonWildcardTypeArguments (ExplicitGenericInvocationSuffix | this Arguments) 这个 [参数] 超级超级后缀 文字 新创作者 标识符 { .标识符 }[ 标识符后缀] 基本类型 {[]} .class 无效类

相关产生式以粗体显示。我们可以看到转换表达式匹配产生式Expression3 : (Expression|Type) Expression3。方法调用通过产生式Primary: Identifier {. Identifier }[IdentifierSuffix] 匹配产生式Expression3 : Primary {Selector} {PostfixOp}。综上所述,我们看到方法调用表达式将被视为一个单元(Expression3),由演员表执行。

嗯,优先级图表更容易遵循... ;)

【讨论】:

  • 这似乎与我从 Eclipse 收到的消息一致。你知道 JLS 有什么可以支持这一点的吗?我没能找到它(这让我很惊讶。我一定只是在我的 Google-fu 中使用了错误的关键字。)
  • @glowcoder:考虑研究Java语言规范中指定的grammar,特别是Expression3的定义。
  • 不幸的是,我不知道官方 Java 出版物中有任何关于运算符优先级的精辟总结。正如@Chris 所说,你必须从语法中解开它。其他人也做过这样的分析,例如Sedgewick and Wayne
  • 哇。感谢您的编辑,它绝对“把事情弄清楚了”(至少对于我们这些能够搞砸语法的人来说)。你知道,对于一群如此专注于确保语言中的一切都一样简单的人为了尽可能地理解,并使事情可维护,看到语法元素名称的选择如此糟糕是令人惊讶的。想象一下使用以这种方式命名变量的代码。 (好吧,我们不必想象,我们以前做过,做的时候会抱怨!)
【解决方案2】:

Method call has a higher operator precedence than type casting,所以(C) a.foo() 将首先调用a.foo() 并将结果转换为类型C。相反,((C) a).foo() 首先将a 转换为C,然后调用其foo() 方法。

【讨论】:

  • 那个链接好像坏了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-23
  • 2012-10-24
  • 1970-01-01
  • 1970-01-01
  • 2015-07-04
  • 2015-08-12
相关资源
最近更新 更多