Java中变量的作用域

Java中变量的作用域,java,scoping,Java,Scoping,在Java中,在使用方法之前,不需要物理地声明方法。同样的事情不适用于变量。 为什么会这样?这仅仅是因为遗留的原因,即Java的创建者不想这样做,还是根本不可能 例如 如果我想让我的Java编译器支持这种正向引用,那么一般的想法是什么? 我知道会有循环依赖的问题,我们需要小心。但除此之外,我真的不明白为什么不可能 [编辑]好的,这是我对如何做到这一点的初步想法。 在分析代码时,编译器将为给定范围内的变量构建依赖关系图。如果它看到一个循环,即int a=b;int b=a,则会抛出一个错误。如果没

在Java中,在使用方法之前,不需要物理地声明方法。同样的事情不适用于变量。 为什么会这样?这仅仅是因为遗留的原因,即Java的创建者不想这样做,还是根本不可能

例如

如果我想让我的Java编译器支持这种正向引用,那么一般的想法是什么? 我知道会有循环依赖的问题,我们需要小心。但除此之外,我真的不明白为什么不可能

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

重述问题: 假设我正在尝试构建自己的Java方言,它支持这种范围界定。我的主要问题是,你能给我一些如何做的想法吗


谢谢

这与初始化的顺序有关。字段从上到下初始化。在您的示例中,当field1尝试在初始值设定项中引用field2时,后者本身尚未初始化

关于正向引用的规则旨在抓住这个问题最明显的例子。它并不是包罗万象;例如,您仍然可以执行以下操作:

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

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

这与初始化顺序有关。字段从上到下初始化。在您的示例中,当field1尝试在初始值设定项中引用field2时,后者本身尚未初始化

关于正向引用的规则旨在抓住这个问题最明显的例子。它并不是包罗万象;例如,您仍然可以执行以下操作:

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

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

我将给您一段简单的代码:

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;
}
foo和bar的价值观是什么?哪个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的值取决于执行顺序,使用词法/语义分析器可能很难检测此类内容。

我将给您一段简单的代码:

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;
}
foo和bar的价值观是什么?哪个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的值取决于执行顺序,可能很难用词法/语义分析器检测此类内容。

根据,类变量的初始化按文本顺序从上到下进行:

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

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

根据,类变量的初始化按文本顺序从上到下进行:

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




所以,如果您让自己的编译器识别前向类变量声明,那么它违反了Java语言规范。

在定义和赋值之前,field1如何知道field2的值

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

我知道,我认为编译器应该能够在这里发出一个关于循环依赖的错误。我的意思是,在代码分析阶段检测这种循环是非常可行的。如果第二个变量设置为编译时不可确定的,但在执行时会怎样?私有字段应设置为什么?虽然它是“可行的”,但探测无法解决的情况并不是“铁的”。编译器应该是铁板一块的——不管怎么说,实现了什么?如果我的措辞对我要问的问题给出了错误的想法,那就很抱歉了。刚刚更新了问题。如果你有问题,请再看一次moment@OneTwoThree我提供了另一个有问题的案例。我将进一步研究你的问题,因为这是一个有趣的问题:我知道,我认为编译器应该能够在这里发布一个关于循环依赖的错误。我的意思是,在代码分析阶段检测这种循环是非常可行的。如果第二个变量在编译时设置为不可确定的,但在执行时设置为可确定的,该怎么办?私有字段应设置为什么?虽然它是“可行的”,但探测无法解决的情况并不是“铁的”。编译器应该是铁板一块的——不管怎么说,实现了什么?如果我的措辞对我要问的问题给出了错误的想法,那就很抱歉了。刚刚更新了问题。如果你有问题,请再看一次moment@OneTwoThree我提供了另一个有问题的案例。我将进一步研究您的问题,因为这是一个有趣的问题:假设您是执行行private int field1=field2的运行时;您应该为field1设置什么值?要回答您自己的问题,请设身处地考虑编译器。假设field1被赋值时field2是可访问的,您希望它被赋值为0、3或其他值吗?我不认为3是一个合理的选择,因为构造函数必须按顺序完成赋值;0只会让代码变得混乱。任何检测图循环的算法的计算复杂度是多少?是否值得将其添加到每个汇编中?要回答这个问题,请回答;允许这种语言特性有什么好处?复杂性不应该真的很重要,是吗?这是在编译时完成的;您应该为field1设置什么值?要回答您自己的问题,请设身处地考虑编译器。假设field1被赋值时field2是可访问的,您希望它被赋值为0、3或其他值吗?我不认为3是一个合理的选择,因为构造函数必须按顺序完成赋值;0只会让代码变得混乱。任何检测图循环的算法的计算复杂度是多少?是否值得将其添加到每个汇编中?要回答这个问题,请回答;允许这种语言特性有什么好处?复杂性不应该真的很重要,是吗?这是在编译时完成的。这就是我一直在等待的。+1引用规范,正好解释了它的用途。只需更新问题。请看一下,如果你有moment@OneTwoThree当然,您可以这样做,但我的观点是,它将不再是正式的Java。假设我正在尝试构建自己的Java方言,它支持这种范围界定。我的主要问题是,你能给我一些关于如何做到这一点的想法吗?这是我一直在等待的。+1引用规范,正好解释了它的用途。只需更新问题。请看一下,如果你有moment@OneTwoThree当然,您可以这样做,但我的观点是,它将不再是正式的Java。假设我正在尝试构建自己的Java方言,它支持这种范围界定。我的主要问题是,你能给我一些如何做的想法吗?关于你的例子,如果你泄露了这个引用,最终字段也是如此。关于你的例子,如果你泄露了这个引用,最终字段也是如此。我想他的观点是,method1如何在定义和分配method2之前知道如何调用它。。。我猜是块?我想他的观点是,method1如何在定义和分配给method2之前知道如何调用它。。。我想是吧?