【问题标题】:How a static variable is accessible before the declaration?在声明之前如何访问静态变量?
【发布时间】:2011-04-11 13:42:39
【问题描述】:
public class Main {

    static int x = Main.y;
//  static int x = y; //Not allowed; y is not defined
    static int y = x;
    public static void main(String[] args) {
        System.out.println(x);//prints 0
    }
}

为什么我可以在课堂上使用 y,但不能直接使用?

y 是什么时候定义的?

【问题讨论】:

    标签: java static-variables class-variables


    【解决方案1】:

    也许编译器在堆栈中创建具有默认值的静态变量的引用,当它被创建时,然后分配提供的值。

    【讨论】:

      【解决方案2】:

      静态变量是在类加载期间按照类中的声明顺序定义的。当 JVM 将加载 Main 类时,将定义 x,然后定义 y。这就是为什么在初始化x 时不能直接使用y,你创建了一个称为前向引用的东西,你引用了一个当前未定义的变量,这对编译器来说是非法的。

      使用Main.y时,我认为会发生以下情况:

      • 你加载Main,调用x初始化
      • 当您将x 定义为等于Main.y 时,编译器会看到对类的引用,因此它将结束将x 定义为类Main 的成员y 的当前值.它将这种情况视为Main 是一个不同的类。

      请注意,在这种情况下,在初始化x 时,y 目前还没有定义。所以x 的值为0

      【讨论】:

      • 如果在我的示例中将 y 设置为 10,x 仍然会变为 0,因此即使加载了类,变量也不会被赋予其值,只是默认值。
      【解决方案3】:

      管理对类变量的前向引用的精确规则在 JLS 的 §8.3.2.3 部分中进行了描述:

      8.3.2.3 初始化时使用字段的限制

      成员的声明需要 在使用之前以文本形式出现 仅当成员是实例时 (分别为static)类的字段 或接口 C 和所有的 以下条件成立:

      • 使用发生在实例(分别为static)变量中 C 或实例中的初始化程序 (分别为static)的初始化器 C.
      • 用法不在作业的左侧。
      • 用法是通过一个简单的名称。
      • C 是包含用法的最内层类或接口。

      如果有任何一个,就会发生编译时错误 以上四项要求不 遇到了。

      这意味着编译时错误 测试程序的结果:

        class Test {
            int i = j;  // compile-time error: incorrect forward reference
            int j = 1;
        }
      

      而以下示例编译 没有错误:

        class Test {
            Test() { k = 2; }
            int j = 1;
            int i = j;
            int k;
        }
      

      即使构造函数 (§8.8) for Test 指的是 被声明为三行的字段 k 稍后。

      这些限制旨在 捕获,在编译时,循环或 否则格式错误的初始化。 因此,两者:

      class Z {
        static int i = j + 2; 
        static int j = 4;
      }
      

      和:

      class Z {
        static { i = j + 2; }
        static int i, j;
        static { j = 4; }
      }
      

      导致编译时错误。 未签入按方法的访问 这样,所以:

      class Z {
        static int peek() { return j; }
        static int i = peek();
        static int j = 1;
      }
      class Test {
        public static void main(String[] args) {
            System.out.println(Z.i);
        }
      }
      

      产生输出:

      0
      

      因为 i 的变量初始化器 使用类方法 peek 访问 j之前的变量j的值 已由其变量初始化 初始化器,此时它仍然 有它的默认值(§4.12.5)

      【讨论】:

        【解决方案4】:

        我会假设通过使用该类,编译器会推迟查找变量,直到该类完成,所以它会找到 y,但如果你只是像注释一样定义它,它还没有定义,所以它失败了

        p>

        【讨论】:

        • 虽然我很惊讶它让你这样做
        【解决方案5】:

        你不被允许这样做,因为它没有意义。唯一可能的解释是 y 被初始化为零,而您已经有两种说法。你不需要这个。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-08-31
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多