为什么java中静态成员的顺序很重要?

为什么java中静态成员的顺序很重要?,java,static,initialization,Java,Static,Initialization,为什么java中静态成员的顺序很重要 例如 这是非常令人困惑的。所以在Java中是不允许的。 主要原因是初始化命令 b Java中允许间接正向引用 public class Test { int i = c(); int c() { return c; } int c = 1; } c必须准确定义变量声明或初始化的执行顺序, 这是java中如何实现的唯一定义。 在java中,这种排序是从上到下的 定义良好的顺序提供了一种实现可预测结果的方法 如果你设计好你的程序,你就不会有这个问题。Jav

为什么java中静态成员的顺序很重要

例如

这是非常令人困惑的。所以在Java中是不允许的。 主要原因是初始化命令

b Java中允许间接正向引用

public class Test {
int i = c();
int c() { return c; }
  int c = 1;
}
c必须准确定义变量声明或初始化的执行顺序, 这是java中如何实现的唯一定义。 在java中,这种排序是从上到下的

定义良好的顺序提供了一种实现可预测结果的方法


如果你设计好你的程序,你就不会有这个问题。

Java类中静态成员的顺序是不相关的。代码的编译方式完全相同。另外,您的示例本质上是没有意义的,因为您只是在更改两个相同类的变量名


编辑:由于您更改了问题,我将向您介绍ykaganovich关于相互分配预先声明的引用变量的回答。您最初的问题是我上面一段中的答案。

Java类中静态成员的顺序是不相关的。代码的编译方式完全相同。另外,您的示例本质上是没有意义的,因为您只是在更改两个相同类的变量名


编辑:由于您更改了问题,我将向您介绍ykaganovich关于相互分配预先声明的引用变量的回答。你最初的问题是我上面一段中的答案。

如果你真的给变量赋值,这很重要

public class A {
  static int i = 0;
  static int c = i; //fine
}
vs

**更新问题**

啊,我看你明白这是不允许的,但你想知道为什么

让我们让它更有趣一点:

  public class A {
    static int c = boom();
    static int i = bam();

    private static int bam() {
      return c + 2;
    }

    private static int boom() {
      return i + 1;
    }

    public static void main(String[] args) throws Exception {
      System.out.println("i: " + i);
      System.out.println("c: " + c);
    }
  }
输出:

i: 3 
c: 1
如果移动i和c:

static int i = bam();
static int c = boom();
你会得到:

i: 2
c: 3
这只是为了说明顺序很重要

至于为什么变量赋值中不允许向前引用,您希望这段代码做什么

static i = c;
static c = i++;
答案实际上是明确的,因为Java必须按照定义的特定顺序处理它。因此,这应该相当于:

static i = 0;
static c = 0;
static {
  i = c;
  c = i++;
}

但第一种形式非常混乱,因此容易出错。我猜这就是为什么它被禁止的原因。

如果你真的给变量赋值,这很重要

public class A {
  static int i = 0;
  static int c = i; //fine
}
vs

**更新问题**

啊,我看你明白这是不允许的,但你想知道为什么

让我们让它更有趣一点:

  public class A {
    static int c = boom();
    static int i = bam();

    private static int bam() {
      return c + 2;
    }

    private static int boom() {
      return i + 1;
    }

    public static void main(String[] args) throws Exception {
      System.out.println("i: " + i);
      System.out.println("c: " + c);
    }
  }
输出:

i: 3 
c: 1
如果移动i和c:

static int i = bam();
static int c = boom();
你会得到:

i: 2
c: 3
这只是为了说明顺序很重要

至于为什么变量赋值中不允许向前引用,您希望这段代码做什么

static i = c;
static c = i++;
答案实际上是明确的,因为Java必须按照定义的特定顺序处理它。因此,这应该相当于:

static i = 0;
static c = 0;
static {
  i = c;
  c = i++;
}

但第一种形式非常混乱,因此容易出错。我猜这就是为什么它被禁止的原因。

静态变量init和静态块执行的顺序也提供了一种执行可预测操作的方法,在这种方法中,以后的变量可以依赖于已经初始化/处理的变量

静态变量init和静态块执行的顺序还提供了一种执行可预测操作的方法,在这种方法中,以后的变量可以依赖于已经初始化/处理的变量

这只是java语言的语法。静态块都在程序运行时初始化。举个例子:

public class A {

    public static void main(String[] args) {
        // some code
    }

    public void play() {
        // some code
    }
}
JVM如何知道启动这个程序?它是否创建类A的实例以了解如何运行它?否-因为主方法声明为静态,所以它在运行时初始化,检测到主方法,程序可以运行

这与C和C++相同。

这适用于任何静态变量或方法。它们都是在程序运行时初始化的。如果您想要创建一个类,并且您需要确保它立即具有某些可用的变量,即类范围内的变量,该怎么办?使它们静止。类似地,可以创建静态块,如下所示:

static {
    // whatever code is needed for initialization goes here
}
这允许在启动时运行简单变量之外的更复杂的代码。它还允许更好的内存分配和使用。有关更多信息,请参阅

编辑:基于更新的问题

我不知道如何回答你的问题

静态变量/块都在运行时初始化。尽管如此,JVM仍然必须单独处理每件事情,这意味着它需要某种顺序。如果将包含int a=c的静态块放在两行静态声明之后,就可以了

如果您将静态声明放在前面,JVM就不知道您所指的是什么,并且会抱怨

为什么会这样?这只是语言的语法。没有比这更好或更详细的理由了。你可以说它应该把所有的东西都载入内存,然后检查以前存在的所有东西 做任何事情,但这将是资源的沉重和内存的浪费


我想我不能给你一个更好或更详细的理由

这只是java语言的语法。静态块都在程序运行时初始化。举个例子:

public class A {

    public static void main(String[] args) {
        // some code
    }

    public void play() {
        // some code
    }
}
JVM如何知道启动这个程序?它是否创建类A的实例以了解如何运行它?否-因为主方法声明为静态,所以它在运行时初始化,检测到主方法,程序可以运行

这与C和C++相同。

这适用于任何静态变量或方法。它们都是在程序运行时初始化的。如果您想要创建一个类,并且您需要确保它立即具有某些可用的变量,即类范围内的变量,该怎么办?使它们静止。类似地,可以创建静态块,如下所示:

static {
    // whatever code is needed for initialization goes here
}
这允许在启动时运行简单变量之外的更复杂的代码。它还允许更好的内存分配和使用。有关更多信息,请参阅

编辑:基于更新的问题

我不知道如何回答你的问题

静态变量/块都在运行时初始化。尽管如此,JVM仍然必须单独处理每件事情,这意味着它需要某种顺序。如果将包含int a=c的静态块放在两行静态声明之后,就可以了

如果您将静态声明放在前面,JVM就不知道您所指的是什么,并且会抱怨

为什么会这样?这只是语言的语法。没有比这更好或更详细的理由了。你可以争辩说它应该把所有的东西都加载到内存中,然后在做任何事情之前检查所有其他存在的东西,但这将是一种资源浪费和内存浪费

我想我不能给你一个更好或更详细的理由

为什么Java被设计成这种顺序会产生不同

您的程序是这样设计的,这种排序会产生不同。您所声明的变量的值是相互依赖的,因此必须定义一些顺序,并且自上而下是Java和大多数语言中定义的。您编写的程序在自上而下的顺序中没有意义。所以,把它修好

为什么Java被设计成这种顺序会产生不同


您的程序是这样设计的,这种排序会产生不同。您所声明的变量的值是相互依赖的,因此必须定义一些顺序,并且自上而下是Java和大多数语言中定义的。您编写的程序在自上而下的顺序中没有意义。所以,把它修好。我试着总结一下答案。欲了解更多信息,请阅读以下答案:

java中的转发引用为:

static int i = c;
static int c = i++;
这是非常令人困惑的。所以在java中是不允许的

b您必须准确定义变量声明的执行顺序, 这是java中如何实现的唯一定义。 在java中,这种排序是从上到下的

c明确的顺序提供了一种实现可预测结果的方法


d如果你的程序设计得好,你就不会有这个问题。

我试着总结一下答案。欲了解更多信息,请阅读以下答案:

java中的转发引用为:

static int i = c;
static int c = i++;
这是非常令人困惑的。所以在java中是不允许的

b您必须准确定义变量声明的执行顺序, 这是java中如何实现的唯一定义。 在java中,这种排序是从上到下的

c明确的顺序提供了一种实现可预测结果的方法


d如果你的程序设计得很好,你就不会有这个问题。

即使我能猜出你在问什么,你的示例代码并没有演示它,我真想知道为什么没有人注意到这一点。我甚至检查了你的问题的整个修订历史,没有发现一个程序实例会产生编译器错误

但是,让我向您展示一个示例,它确实会产生您可能想到的编译器错误:

public class Test {
  int i = c;
  int c = 1;
}
这里发生的是在i的初始值中引用c。因此,您试图读取一个尚未初始化的变量。请注意,这与声明顺序编译时无关,只与初始化顺序运行时有关。在Java中,与所有其他类似语言一样,成员声明的顺序除了暗示成员初始值设定项的执行顺序之外,不起任何作用

Java有一个检查,它阻止一个初始值设定项读取初始值设定项尚未运行的变量。Java还有许多其他类似的检查,因为它的设计是为了尽力保护程序员不犯愚蠢的错误。用詹姆斯·戈斯林的话来说,爪哇本来就是一种蓝领语言。这应该能回答你为什么的问题

请注意,特定的编译器检查w 这里讨论的e非常弱,只适用于最明显的情况。考虑上述程序的简单变化:

public class Test {
  int i = c();
  int c() { return c; }
  int c = 1;
}

这里没有产生错误。Java并没有检查您在从初始值设定项调用的任何方法中实际执行的操作。

即使我可以猜到您在这里提出的问题,您的示例代码并没有演示它,我真的很想知道为什么没有人注意到这一点。我甚至检查了你的问题的整个修订历史,没有发现一个程序实例会产生编译器错误

但是,让我向您展示一个示例,它确实会产生您可能想到的编译器错误:

public class Test {
  int i = c;
  int c = 1;
}
这里发生的是在i的初始值中引用c。因此,您试图读取一个尚未初始化的变量。请注意,这与声明顺序编译时无关,只与初始化顺序运行时有关。在Java中,与所有其他类似语言一样,成员声明的顺序除了暗示成员初始值设定项的执行顺序之外,不起任何作用

Java有一个检查,它阻止一个初始值设定项读取初始值设定项尚未运行的变量。Java还有许多其他类似的检查,因为它的设计是为了尽力保护程序员不犯愚蠢的错误。用詹姆斯·戈斯林的话来说,爪哇本来就是一种蓝领语言。这应该能回答你为什么的问题

请注意,我们在这里讨论的特定编译器检查非常弱,只适用于最明显的情况。考虑上述程序的简单变化:

public class Test {
  int i = c();
  int c() { return c; }
  int c = 1;
}


这里没有产生错误。Java没有检查您在初始化器中调用的任何方法中实际做了什么。

我不明白。您想了解什么?如果您有更深入的问题,或具体的问题,请随时编辑您的问题并提问。谢谢!我的问题是为什么java是这样设计的,我不明白。您想了解什么?如果您有更深入的问题,或具体的问题,请随时编辑您的问题并提问。谢谢!我的问题是为什么java是这样设计的。好吧,也许我应该重新表述我的问题。静态初始值设定项顺序是相关的。@JohnN这不是一个坏问题,如果我的回答是简短的,很抱歉。只是想帮点忙。好吧,也许我应该重新措辞我的问题。静态初始值设定项顺序是相关的。@JohnN这不是一个坏问题,如果我的回答是简短的,很抱歉。只是想帮点忙。谢谢!但这并不能回答问题。说得好!我不确定非静态变量是否也允许。非常好的解释谢谢!但这并不能回答问题。说得好!我不确定非静态变量是否也允许。非常好的解释。你能解释一下你对可预测操作的意思吗?你能解释一下你对可预测操作的意思吗?我不确定这只是巧合,就像你对单词和字符串的例子一样。JAVA/C的设计者有理由这么做。@JohnN:为了更简洁,我删除了这一点。它允许更好地使用内存和其他东西。检查我的编辑上的链接。这就是静态代码块的要点。此外,静态变量是类范围的,而不是特定于对象的。无论创建多少对象,您只需要一个类变量。明白吗?我明白什么是静态块或变量。但问题是为什么静态声明的顺序很重要。出于同样的原因,实例变量顺序也很重要。如果您执行问题中的代码,就可以了,没有区别。如果您尝试在分配变量的行之前增加变量,则会引发投诉。这就是系统的逻辑。不管它在运行时加载所有内容,它仍然会一个接一个地处理所有内容,因此必须以某种顺序获取信息。我不能投票,因为我已经投票支持了您的答案。你读过ykaganovich或Ashish的答案吗?我不确定这只是巧合,就像你的例子中的单词和字符串一样。JAVA/C的设计者有理由这么做。@JohnN:为了更简洁,我删除了这一点。它允许更好地使用内存和其他东西。检查我的编辑上的链接。这就是静态代码块的要点。此外,静态变量是类范围的,而不是特定于对象的。无论创建多少对象,您只需要一个类变量。明白吗?我明白什么是静态块或变量。但问题是为什么静态声明的顺序很重要。出于同样的原因,实例变量顺序也很重要。如果您执行问题中的代码,就可以了,没有区别。如果您尝试在分配变量的行之前增加变量,则会引发投诉。这就是系统的逻辑。无论它是否在运行时加载所有内容,它都会
ill会一个接一个地处理所有信息,因此必须以某种顺序获取信息。我无法投票,因为我已经投票给了你的答案。你读过ykaganovich或Ashish的答案吗?谢谢你的回答。当然,我的程序是这种Java行为的原因。但问题是:为什么Java在我的程序中会这样做呢?谢谢你的回答。当然,我的程序是这种Java行为的原因。但问题是:为什么Java对我的程序有这样的行为。Java中允许向前引用。你确定吗?Java 1.7编译器不允许“正向引用”错误。这里Java只是阻止您读取初始化器尚未运行的变量。前向引用的概念比这更一般:例如,您当然可以调用在调用位置下方定义的方法。为了使其与您的答案完全相关,请声明static int c{return c;},并将直接读取替换为方法调用:static i=c;。Java中允许转发引用。您确定吗?Java 1.7编译器不允许“正向引用”错误。这里Java只是阻止您读取初始化器尚未运行的变量。前向引用的概念比这更一般:例如,您当然可以调用在调用位置下方定义的方法。为了使其与您的答案完全相关,请声明static int c{return c;},并将直接读取替换为方法调用:static i=c;。谢谢你的回答,谢谢你的回答,