【问题标题】:Order of execution of methods describing an instance and an argument in Java?Java中描述实例和参数的方法的执行顺序?
【发布时间】:2012-11-23 09:07:43
【问题描述】:

在声明中:

fooFunc().barFunc(bazFunc());

barFunc() 显然不能在 bazFunc()fooFunc() 都完成之前执行。

但是fooFunc()bazFunc()的执行顺序有保证吗?

相关(但不同!)问题: Order of execution of parameters guarantees in Java?

【问题讨论】:

  • 第一。 fooFunc(),比bazFunc(),最后barFunc()
  • 可以说,如果您需要在这样的单个语句中保证执行顺序,那么您做错了。编辑:这并不是说这不是一个好问题或没有确凿的答案,只是如果你发现自己在实际情况下问这个问题,你可能想找出导致到这行代码。
  • @Kiyura 你在说什么?这里绝对保证执行顺序。
  • 我确实同意@Kiyura - 你应该避免编写这样的代码 - 但值得知道,因为通过了解这一点可以发现细微的错误。
  • 我要补充一点,编译器/运行时可以重新排序执行,只要效果相同。

标签: java


【解决方案1】:

首先是fooFunc,然后是bazFunc,最后是barFunc

以下是一些演示代码:

public class OrderJava {
  public static void main(String[] args) {
    fooFunc().barFunc(bazFunc());
  }

  public static Bar fooFunc() {
    System.out.println("I am fooFunc!");
    return new Bar();
  }

  public static class Bar {
    public void barFunc(Object o) {
      System.out.println("I am barFunc!");
    }
  }

  public static Object bazFunc() {
    System.out.println("I am bazFunc!");

    return null;
  }
}

这段代码的输出是:

I am fooFunc!
I am bazFunc!
I am barFunc!

【讨论】:

  • 投反对票。问题是“执行顺序是否得到保证?” (隐含地:通过(语言/JVM)规范),而不是“您能否提供一个示例来演示一个编译器和一个 JVM 会发生什么以及一个示例”。
  • 你的投票标准真的很低。对这样的问题进行演示很有用;虽然我仍然认为你的答案应该是被接受的。
  • 经过反思,你是对的,我认为我过于热心了。我从 JLS 给出的例子并不比你的答案有用得多,因为 JLS 的例子是多么模糊......没有被否决!
【解决方案2】:

JLS,Java SE 7 版有以下示例,它在bazFunc() 之前表示它是fooFunc(),但是我只能找到示例 - 我还没有找到指定它的关联语句:

示例 15.12.4.1-2。方法调用期间的评估顺序

作为一部分 在实例方法调用(§15.12)中,有一个表达式 表示要调用的对象。这个表达式似乎完全 在方法的任何参数表达式的任何部分之前评估 调用被评估。因此,例如,在:

class Test2 { 

    public static void main(String[] args) { 
        String s = "one"; 
        if (s.startsWith(s = "two")) 
            System.out.println("oops"); 
    } 
}

s".startsWith" 之前的出现首先被评估,在 参数表达式s = "two"。因此,参考 字符串"one" 在本地之前被记住为目标引用 变量 s 更改为引用字符串 "two"。结果, 为目标对象 "one" 调用 startsWith 方法,并带有参数 "two",所以调用结果为假,为字符串"one" 不以"two" 开头。由此可见,测试程序不 打印"oops"

【讨论】:

    【解决方案3】:

    这方面的文档是15.12.4. Run-time Evaluation of Method Invocation

    它说“在运行时,方法调用需要五个步骤。首先,可以计算目标引用。第二,评估参数表达式。第三,检查要调用的方法的可访问性。第四,找到要执行的方法的实际代码。第五,创建一个新的激活框架,必要时进行同步,并将控制权转移到方法代码。”

    在示例中,fooFunc() 被调用作为计算目标引用的一部分,bazFunc() 是参数表达式之一,因此必须首先调用 fooFunc()

    【讨论】:

    • 只是为了增加这个答案 - Section 15.12.4.1. Compute Target Reference (If Necessary) 的第 2 部分继续澄清:“表达式 Primary 被评估,结果被用作目标引用”(在这种情况下,Primary 是产生指fooFunc(),它的方法被调用的对象。(编辑:实际上,我可能是唯一一个在这里感到困惑的人。我认为“目标引用”可能只是指方法本身。继续。)
    【解决方案4】:

    fooFunc() 将首先执行,然后是 bazFunc(),最后是 barFunc()

    我们都同意fooFunc() 必须在barFunc() 进行任何操作之前执行。

    鉴于bazFunc() 只会在barFunc() 需要它的参数时才被调用,按理说这会发生在fooFunc() 之后。

    【讨论】:

    • 你能用规范参考来支持吗?
    • 这是有道理的,因为对象访问器运算符 (.) 从左到右计算,但我同意它需要一个源。
    • @bacar 我相信它符合逻辑,我会编辑我的答案。
    • “鉴于bazFunc() 只会在barFunc() 需要它的参数时被调用”...我不认为这是给定的。
    • 我认为您错过了问题的症结所在。在进行方法调用之前,需要两条信息:fooFunc() 返回的值(要在其中找到方法的对象),以及barFunc() 返回的值(作为方法传递给方法的值)第一个参数)。它们在其他方面是不相关的,只是在执行该语句时它们都需要。问题是它们中的哪一个将由规范首先执行。你的回答基本上是“我认为很明显这个会先出现。”
    猜你喜欢
    • 2019-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-16
    • 1970-01-01
    • 2011-01-13
    • 2015-12-10
    • 1970-01-01
    相关资源
    最近更新 更多