为什么java中静态成员的顺序很重要?
E.g。
public class A {
static int i= 1;
static int c = i;
int a = c; <<------ ok
}
VS
public class B {
int a = c; <<--- compile error
static int c = 1;
static int i = c;
}
为什么Java的设计使得这种排序有所不同? (我根据ykaganovich的回答编辑了我的问题)
编辑:谢谢大家的帮助! 我用非静态变量测试了我的例子。它具有完全相同的行为,因此静态不起任何作用。这个问题具有误导性(至少对我而言)。我会尝试总结你的答案。
修改 2 :
我会尝试总结答案。欲了解更多信息,请阅读以下答案:)
a)Java中的直接前向引用:
static int i = c;
static int c = 1;
非常混乱。所以在Java中不允许这样做。 主要原因是初始化顺序。
b)Java中允许间接前向引用
public class Test {
int i = c();
int c() { return c; }
int c = 1;
}
c)您必须准确定义变量声明(或初始化)的执行顺序, 它的唯一定义是如何在java中完成的。 在java中,这种排序从上到下。
d)明确定义的顺序提供了一种可预测结果的方法。
e)如果你很好地设计你的程序,你将不会遇到这个问题。
答案 0 :(得分:5)
如果你实际上是为变量赋值,那就很重要了。
public class A {
static int i = 0;
static int c = i; //fine
}
VS
public class B {
static int c = i; // compilation error
static int i = 0;
}
**更新问题**
啊,我看到你明白这是不允许的,但你想知道原因。
让我们更有趣一点:
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++;
}
但第一种形式非常混乱,因此容易出错。我的猜测就是它被禁止的原因。
答案 1 :(得分:2)
Java类中静态成员的顺序无关紧要。代码以完全相同的方式编译。此外,您的示例基本上没有意义,因为您只是为两个相同的类更改变量名。
编辑:既然你改变了问题,我将指出ykaganovich关于将预先声明的参考变量分配给对方的答案。您的原始问题在我上面的段落中是回答。
答案 2 :(得分:2)
静态变量init和静态块执行的顺序还提供了一种方法来执行可预测的操作,以后变量可以依赖于已经初始化/已处理的变量。
答案 3 :(得分:1)
这只是 java语言的语法。静态块都在程序运行时初始化。举个例子:
public class A {
public static void main(String[] args) {
// some code
}
public void play() {
// some code
}
}
JVM如何知道启动此程序?它是否创建了A类的实例以了解如何运行它?否 - 因为main方法声明为static,它在运行时初始化,检测到主方法并且程序可以运行。
这与C#和C ++相同。
这适用于任何静态变量或方法。它们都是在程序运行时初始化的。如果你想创建一个类并且你需要确保它有一些可用的变量 - 类变量的变量怎么办?让它们变得静止。同样,您可以创建静态块,如下所示:
static {
// whatever code is needed for initialization goes here
}
这允许在启动时运行除简单变量之外的更复杂的代码。它还允许更好的内存分配和使用。有关详细信息,请参阅here。
编辑:(根据更新的问题)
我不确定如何回答你的问题。
静态变量/块都在运行时初始化。尽管如此,JVM仍然必须单独处理每个事物,这意味着它需要某种顺序。如果在两行静态声明之后放置包含int a = c
的静态块,那很好。
如果您之前放置静态声明,JVM不知道您所指的是什么并抱怨。
至于为什么会这样?这只是语言的语法。没有更好或更详细的理由。您可以说它应该将所有内容加载到内存中,然后在执行任何操作之前检查其他所有内容,但这会耗费大量资源并浪费内存。
我认为我不能给你一个更好或更详细的理由!
答案 4 :(得分:1)
为什么Java的设计使得这种排序有所不同?
您的程序的设计使得这种排序有所不同。您声明的值是相互依赖的变量,因此必须定义一些排序,从上到下是Java中定义的内容,实际上是大多数语言。您编写的程序在从上到下排序中没有意义。所以要修好它。
答案 5 :(得分:1)
我尝试尝试总结答案。欲了解更多信息,请阅读下面的回答:)
a)java中的前向引用:
static int i = c;
static int c = i++;
非常混乱。所以在java中不允许这样做。
b)您必须准确定义变量声明的执行顺序, 它的唯一定义是如何在java中完成的。 在java中,这种排序从上到下。
c)明确定义的顺序提供了一种可预测结果的方法。
d)如果你很好地设计你的程序,你将不会遇到这个问题。
答案 6 :(得分:1)
即使我能猜出你在这里问的是什么,你的示例代码也没有证明它,我真的很想知道没有人注意到这一点。我甚至检查了你的问题的整个修订历史,并且找不到一个实际产生编译器错误的程序的单个实例。
但是,让我向您展示 产生编译器错误的示例,您可能会想到:
public class Test {
int i = c;
int c = 1;
}
这里发生的是您在c
的初始值设定项中引用i
。因此,您正在尝试读取尚未初始化的变量。请注意,这与声明顺序(编译时)无关,只与初始化顺序(运行时)有关。在Java中,与所有其他类似语言一样,成员声明的顺序不起作用,除非暗示成员初始化程序的执行顺序。
Java有一个检查阻止一个初始化程序读取其初始化程序尚未运行的变量。 Java有许多其他类似的检查,因为它旨在努力保护程序员免于犯愚蠢的错误。用James Gosling的话来说,Java本来就是一个蓝领&#34;语言。这应该回答你的原因&#34;问题
请注意,我们在这里讨论的特定编译器检查非常弱,仅适用于最明显的情况。考虑上述程序的这个简单变化:
public class Test {
int i = c();
int c() { return c; }
int c = 1;
}
此处未产生任何错误。 Java并没有检查你从初始化程序调用的任何方法中实际执行的操作。