我对static变量初始化顺序的质疑

computerlibin 2011-04-26 11:14:58
我在网上查了很多资料都是说:java中static变量的初始化要在static块的之前执行,并且这个网页http://blog.csdn.net/ice_kane/archive/2010/01/15/5194168.aspx给出了代码证明。但是我自己写的代码却说明static变量和static块的执行顺序取决于他们在类中的声明顺序,我的代码如下:

public class StaticTest {
static{//静态块在静态变量之前声明
a=100;
}

public static int a=10;

public static void main(String[] args) {
System.out.println(StaticTest.a);//这里打印出的是10,说明public static int a=10;在static块之后 执行
}
}

public class StaticTest {
public static int a=10;//静态变量在静态块之前声明

static{
a=100;
}

public static void main(String[] args) {
System.out.println(StaticTest.a);//这里打印出的是100,说明static块在public static int a=10之后执行
}
}

如果按照静态变量先于static块初始化的理论,两个程序打印出来的应当都是100啊,我就不明白了。。。
我也不知道我说清了没有。。。
...全文
171 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
computerlibin 2011-04-27
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 wangfeiwoyun 的回复:]
难道我回答的不够清楚?哎。。桑心~~~
[/Quote]
你回答的很清楚,只是系统不让我连续三次回复了,现在回复你,呵呵
我还有一点疑问,“1·在(实例/静态)变量初始化器中或者(实例/静态)初始化器中使用”和“4·C是一个最内部的类但是在外部的类中使用”
,是什么意思,什么东东?
wangfeiwoyun 2011-04-27
  • 打赏
  • 举报
回复
难道我回答的不够清楚?哎。。桑心~~~
teemai 2011-04-27
  • 打赏
  • 举报
回复
楼主认真的看下那篇文章吧。
http://blog.csdn.net/ice_kane/archive/2010/01/15/5194168.aspx

那么对于静态变量和静态初始化块之间、变量和初始化块之间的先后顺序又是怎样呢?是否静态变量总是先于静态初始化块,变量总是先于初始化块就被初始化了呢?实际上这取决于它们在类中出现的先后顺序。
computerlibin 2011-04-27
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 ticmy 的回复:]

javap -c Test
[/Quote]
用javap -c 反编译那两个类出现的东西是一样的,这个是什么意思啊?
computerlibin 2011-04-27
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 z070204z 的回复:]

难道只有赋值操作才可以写到前面???我的MyEclipse提示的是未定义。。

public static int a;

static {
a = 100;
System.out.println(a);
}

这样是没问题的。。。
[/Quote]
我也有这个疑问呢,我觉得2楼ticmy说的方法能够解释清楚,但是我现在还没搞懂,呵呵
computerlibin 2011-04-27
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 jiang617325814 的回复:]
静态成员变量和初始化块是按照声明顺序的
[/Quote]
我也觉得是这样的
computerlibin 2011-04-27
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 jiang617325814 的回复:]
public class StaticTest {
static{
System.out.println(a);//出现“非法先前引用”
}
public static int a=10;
public static void main(String[] args) {
System.out.println(StaticTest.a);
}
}
你这边a不是还没有声明……
[/Quote]
你这边a不是还没有声明,就直接使用它的引用了,当然是非法引用了,这句话是什么意思?
computerlibin 2011-04-27
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 huxiweng 的回复:]
楼主认真的看下那篇文章吧。
http://blog.csdn.net/ice_kane/archive/2010/01/15/5194168.aspx

那么对于静态变量和静态初始化块之间、变量和初始化块之间的先后顺序又是怎样呢?是否静态变量总是先于静态初始化块,变量总是先于初始化块就被初始化了呢?实际上这取决于它们在类中出现的先后顺序。
[/Quote]
恩,是我没认真看完那篇文章,现在明白了,但是我还有疑问,为什么
public class StaticTest {
static{
a=20;//这个不会出现“非法先前引用”
System.out.println(a);//这里为什么会出现“非法先前引用”?}
public static int a=10;
public static void main(String[] args) {
System.out.println(StaticTest.a);
}
}
a的声明在静态块之后,但是为什么静态块中a=20;不会出现“非法向前引用”,而System.out.println(a);会出现“非法向前引用”?
jiang617325814 2011-04-27
  • 打赏
  • 举报
回复
public class StaticTest {
static{
System.out.println(a);//出现“非法先前引用”
}
public static int a=10;
public static void main(String[] args) {
System.out.println(StaticTest.a);
}
}
你这边a不是还没有声明,就直接使用它的引用了,当然是非法引用了
jiang617325814 2011-04-27
  • 打赏
  • 举报
回复
静态成员变量和初始化块是按照声明顺序的
jiang617325814 2011-04-27
  • 打赏
  • 举报
回复
初始化顺序:
1.在类加载时候,为类中静态成员变量分配内存空间,并赋默认值
2.执行静态成员变量的初始化操作(初始化块)
3.如果创建类的对象,在堆中为类的实例分配内存空间,实例变量这个时候被初始化为默认值
4.执行实例变量的初始化操作,按声明的顺序
5.执行构造函数
wangfeiwoyun 2011-04-27
  • 打赏
  • 举报
回复
娘了个腿~~fieldSet咋没用啊
wangfeiwoyun 2011-04-27
  • 打赏
  • 举报
回复

public class StaticTest {
static{//静态块在静态变量之前声明
a=100;
}
public static int a=10;

public static void main(String[] args) {
System.out.println(StaticTest.a);//这里打印出的是10,说明public static int a=10;在static块之后 执行
}
}

一个类在你用之前有“装载,链接,初始化”这么几个阶段,链接又有“验证,准备,解析”这三个阶段。
装载就是把2进制的class文件加载到JVM。
链接就是分配内存,将符号引用解析为直接引用还有给变量赋默认值。(静态变量[类变量]就是在这个阶段创建的)
初始化就是执行初始化语句和初始化块。初始化顺序为(见The Java Language Specification§12.4.2):
<fieldset>
9. Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they
were a single block, except that final class variables and fields of interfaces
whose values are compile-time constants are initialized first (§8.3.2.1, §9.3.1,
§13.4.9).
</fieldset>
好,再看你的代码:
public static int a

a这个变量是在准备阶段创建的(链接的第二个阶段),创建玩并给了默认值0,int变量的默认值为0.然后到类的初始化阶段按照文本中出现的先后顺序进行初始化。先执行static块中的,初始化为100,然后再执行你声明时的显示初始化 a=10,最后a的值为10.所以在main中打印的结果就位10了。

再看你的第二个疑问,为什么会有“非法先前引用”的问题。

先看The Java Language Specification§8.3.2.3的描述:
<fieldSet>
The declaration of a member needs to appear textually before it is used only if
the member is an instance (respectively static) field of a class or interface C and
all of the following conditions hold:
• The usage occurs in an instance (respectively static) variable initializer of C
or in an instance (respectively static) initializer of C.
• The usage is not on the left hand side of an assignment.
• The usage is via a simple name.
• C is the innermost class or interface enclosing the usage.
</fieldset>
就是说 如果以下四种情况全部满足,那么类C的成员要在用之前声明:(大概翻译下,不是很准确)
1·在(实例/静态)变量初始化器中或者(实例/静态)初始化器中使用
2·使用时不在赋值语句的左边
3·通过简单名词使用
4·C是一个最内部的类但是在外部的类中使用


public class StaticTest {
static{
System.out.println(a);//static块中使用a符合上述情况,要在使用前声明,所以出现了一个error。
// 如果改为System.out.println(StaticTest.a)就不会报错了。(不符合第3点,没使用简单名称a,而用了StaticTest.a)
}
public static int a=10;
public static void main(String[] args) {
System.out.println(StaticTest.a);
}
}



public class StaticTest {
static{
a=20;//这个a在赋值语句的左边,不符合第2点。所以是可以的。
}
public static int a=10;
public static void main(String[] args) {
System.out.println(StaticTest.a);
}
}

勤于奋 2011-04-27
  • 打赏
  • 举报
回复
看来你是一个爱研究的。学习了。
悟之思语 2011-04-27
  • 打赏
  • 举报
回复
good luck!
computerlibin 2011-04-27
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 nokiaisacat 的回复:]
Java code

public class StaticTest {

static {
a = 100;
}

public static int a;

public static void main(String[] args) {
System.out.println(StaticTe……
[/Quote]
恩,赋值为0是全局变量的默认值,之后执行static块,最后就不执行public static int a;的默认赋值了
nokiaisacat 2011-04-27
  • 打赏
  • 举报
回复

public class StaticTest {

static {
a = 100;
}

public static int a;

public static void main(String[] args) {
System.out.println(StaticTest.a);

}
}



这个运行结果是100,而不是0,说明顺序是这样的,首先创建static的字段,并初始化为0,然后按顺序执行static的赋值语句
z070204z 2011-04-26
  • 打赏
  • 举报
回复
难道只有赋值操作才可以写到前面???我的MyEclipse提示的是未定义。。

public static int a;

static {
a = 100;
System.out.println(a);
}

这样是没问题的。。。
computerlibin 2011-04-26
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 ticmy 的回复:]

javap -c Test
[/Quote]
这个反编译后的东东有点看不懂,吼吼,我还需要好好学习学习!
computerlibin 2011-04-26
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 z070204z 的回复:]

经断点测试,确实是按顺序运行的
[/Quote]
如果是按照顺序执行的为什么这个代码编译时会出现“非法先前引用”的错误
public class StaticTest {
static{
System.out.println(a);//出现“非法先前引用”
}
public static int a=10;
public static void main(String[] args) {
System.out.println(StaticTest.a);
}
}

而下面这个代码不会出现
public class StaticTest {
static{
a=20;//这个不会出现“非法先前引用”
}
public static int a=10;
public static void main(String[] args) {
System.out.println(StaticTest.a);
}
}
真是挺奇怪的
加载更多回复(2)

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧