Java中的变量范围

时间:2014-01-14 20:55:49

标签: java scoping

在Java中,在使用它之前,您没有物理声明方法。同样的事情不适用于变量。 为什么会这样?它只是出于“遗留”的原因(即,Java的创建者不喜欢这样做),还是只是不可能?

例如,

public class Test
{
    // It is OK for meth1 to invoke meth2
    public void meth1() { meth2(); }
    public void meth2() { }

     // But why is it NOT ok for field1 to reference field2
     private int field1 = field2;
     private int field2 = 3;
}

如果我希望我的Java编译器支持这种前向引用,那么关于如何执行它的一般想法是什么? 我知道循环依赖关系存在问题,我们需要谨慎对待。但除此之外,我真的不明白为什么它不可能。

[编辑]好的,这是我最初的想法,如何做到这一点。 在分析代码时,编译器将为给定范围内的变量构建依赖关系图。如果它看到一个循环(即,int a = b; int b = a),那么它会抛出一个错误。如果没有循环,则必须有一些最佳方式来重新排列语句(在场景后面),这样一个字段只会引用在它之前声明的字段,因此它会试图找出顺序。我还没有找到确切的算法,但我认为这是可能的。除非有人能够科学地证明我错了。

回顾一下问题: 说我正在尝试构建自己的Java方言,它支持这种范围。我的主要问题是,你能否就如何做到这一点给我一些想法

由于

4 个答案:

答案 0 :(得分:7)

根据JLS, Section 12.4.1,类变量的初始化从上到下,以“文本顺序”进行:

  

静态初始值设定项和类变量初始值设定项以文本顺序执行,并且可能不引用在声明在使用后以文本方式出现的类中声明的类变量,即使这些类变量在范围内(第8.3.2.3节)。此限制旨在在编译时检测大多数循环或其他格式错误的初始化。

因此,如果您使自己的编译器识别正向类变量声明,那么它就违反了Java语言规范。

答案 1 :(得分:4)

我会给你一段简单的代码:

public class Test
{
    private int foo = bar;
    private int bar = foo;
}

您期望这样做?

我认为Java的设计者已经这样做了,因为实例变量的赋值必须按某种顺序执行。对于Java,它们是向下执行的(从上到下)。

修改

这个怎么样?

public class Test {
    private int foo = quu++;
    private int bar = quu++;
    private int quu = 1;
}

foobar会有什么价值?首先执行哪个quu++语句?

我的观点是,Java设计者必须认为按照您在问题中描述的方式执行此操作是违反直觉的,即使用编译时代码分析进行无序执行。

最终编辑

让事情变得复杂:

class Test {
    private James james = new James(anInt);
    private Jesse jesse = new Jesse(anInt);
    private IntWrapper anInt = new IntWrapper();
}

class James {

    public James(IntWrapper anInt) {
        if(--anInt.value != 0) {
            new Jesse(anInt);
        }
        else {
            anInt.isJames = true;
        }

    }
}

class Jesse {
    public Jesse(IntWrapper anInt) {
        if(--anInt.value != 0) {
            new James(anInt);
        }
        else {
            anInt.isJames = false;
        }
    }
}

class IntWrapper {
    public int value = 99;
    public boolean isJames;
}

我不确定它对你的问题的证明,因为我不确定你的意思。

这里没有循环依赖,但IntWrapper的实例变量isJames的值取决于执行顺序,并且可能很难用词法/语义分析器检测这种东西。

答案 2 :(得分:0)

它与初始化的顺序有关。字段从上到下进行初始化。在您的示例中,当field1尝试在初始化程序中引用field2时,后者尚未自行初始化。

关于前向引用的规则旨在捕获此问题的最明显的案例。它并不能解决所有问题;例如,你仍然可以这样做:

 private int field1 = getField2();
 private int field2 = 3;
 private int getField2() { return field2; }

并将field1初始化为零,您可能期望3

答案 3 :(得分:0)

field1在定义和分配值之前如何知道field2的值?