【问题标题】:Does java forward referencing act differently in different situations?java前向引用在不同情况下的行为是否不同?
【发布时间】:2014-03-01 06:02:48
【问题描述】:

请看一下这个sn-p:

public class A {
    void method() {
        System.out.print(B.j);//This is legal!
        class C {
            void method () {
                System.out.print(j);//This is illegal!
            }
        }
        final int j = 10;
        class D {
            void method() {
                System.out.print(j);//This is legal!
            }
        }
    }
}
class B {
    static int j = 10;
}

我们可以在定义之前访问“B.j”,而在 C 类中访问“final int j”是非法的。

java 编译器是否将本地类视为简单的变量/对象?特别是,这种行为背后的基本原理是什么?我的意思是前向检查适用于 B.j,但不适用于 C 类中的“j”。

【问题讨论】:

  • System.out.print(j) 在类 D 内是合法的

标签: java compiler-construction inner-classes local-class


【解决方案1】:

我相信这是简单的范围界定。如果你用简单的 System.out.println() 调用替换你的内部类,

public class A {
  void method() {
    System.out.print(j);//This is illegal!
    final int j = 10;
    System.out.print(j);//This is legal!
  }
}

你会发现你收到了同样的信息。局部变量的范围从声明它们的地方开始,一直持续到声明它们的块的末尾。

要回答关于 B 的参考的问题:考虑

public class A {
  void method() {
    System.out.print(k);//This is legal!
  }
  int k=17;
}

Java 不是单遍编译。类及其公开的字段和方法可以被前向引用。一个深思熟虑的决定是局部变量不能被前向引用。我猜这是为了让程序员建立受限范围而不必使用额外级别的{} 块语句——如果我引入一个新变量,特别是在初始化时,我不希望任何人在那之前篡改它.

这就是 Java 局部变量的工作方式。这可能不是一个令人满意的答案,但它是我们得到的最好的答案。

【讨论】:

  • 当然你是对的。显然,这都是关于范围的。但为什么我可以访问 B.j?
  • 因为 B.j 是静态的。它不属于任何单个对象或方法或执行路径;它属于 B 类。
  • 我只是将它定义为静态以避免生成对象,即使我再次删除静态关键字它也是合法的(使用 B 类对象)。
  • 我认为这是最好的解释。在 Java 语言规范中很难确定确切的定义,但我认为最好的地方是第 4.12.3 节第 7 节:“每当控制流进入块(第 14.2 节)或 for 语句(第 14.14 节),一个为立即包含在该块或 for 语句中的局部变量声明语句中声明的每个局部变量创建新变量。” docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12
  • 嗯 4.12.3 没有解释为什么只能在声明后引用局部变量,而不是通过整个块。但是第 6.3 节确实:“由块(第 14.2 节)直接包围的局部类声明的范围是直接封闭块的其余部分,包括它自己的类声明。”
【解决方案2】:

设置你的代码不编译的可能性......

当类加载器将 A 类加载到内存中时,B 类也是如此,因为它们在同一个文件中。所以在运行时调用method 时,B.j 已经在堆上分配了。

另一方面,当您在方法中声明变量时,这些变量会在调用方法时存储在堆栈中,按照您编写它们的顺序,所以这里的顺序很重要。

【讨论】:

  • 那么您的意思是编译器将 C 类和 D 类视为变量吗?
  • 声明的顺序在方法内部很重要,但在类内部不重要(除非它是构造函数、初始化块等)
  • 请说出原因。肯定有这个原因。
  • @ktm5124 类加载器并不关心你的类在哪个源文件中。类 A、B、C 和 D 都是在不同时间加载的独立类。事实上,在另一个类中引用可访问字段是合法的,无论它在源代码中的何处声明(在引用之前或之后),而局部变量在声明之前不能被引用。
  • @ktm5124 这个说法不正确:“当类加载器将 A 类加载到内存中时,B 类也是如此,因为它们在同一个文件中。”
猜你喜欢
  • 1970-01-01
  • 2013-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-03
相关资源
最近更新 更多