A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 王红潮 中级黑马   /  2012-9-9 00:38  /  2535 人查看  /  10 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 王红潮 于 2012-9-9 18:39 编辑
  1. public class Test {

  2. static{
  3. b=6;
  4. //System.out.println(b);//这里非法向前引用
  5. }
  6. static int b=8;
  7. static{
  8.    b=10;
  9.    System.out.println("static...b=" + b);
  10. }
  11. public static void main(String[] args) {
  12. System.out.println(Test.b);
  13. }
  14. }
复制代码
上面的b值应该被赋了3次,第一次先赋值为6,第二次才是8,最后一次是10
程序2:
  1. class Test7
  2. {
  3.     {
  4.         a=7;
  5.       //System.out.println("a="+a);   //非法向前引用
  6.      }
  7. int a=9;
  8.   {
  9.     a=11;
  10.      System.out.println("static...a="+a);  //正常打印
  11.   }

  12. public static void main(String[] args) {
  13. System.out.println(new Test7().a);
  14. }

  15. }
复制代码
谢谢大家的回答,我还是有一点模糊的地方,当JVM第一次主动使用某个类时,系统会在类准备阶段为该类的所有静态Field分配内存,然后初始化静态Field就是执行类初始化代码,或者声明类Field时指定的初始值
当java创建一个对象时,系统先为该对象的所有实例Field分配内存(该类已经被加载后),接着程序开始对这些实例变量执行初始化,顺序是“先执行初始化块或者声明Field时指定的初始值

程序3:
  1. public class Test {

  2. static{
  3. b=6;  //对已经定义且开辟内存空间的变量b显示初始化
  4. System.out.println(b);//这里非法向前引用
  5. }
  6. static int b;
  7. public static void main(String[] args) {
  8. System.out.println(Test.b); //结果是6
  9. }
  10. }

复制代码
上面的程序能看出顺序, static int b 肯定先加载进内存,开辟空间,然后由静态代码块按照顺序显示初始化,那么既然代码块里已经显示初始化了,那么在代码块里为什么还是非法向前引用

评分

参与人数 1技术分 +1 收起 理由
创出一片辉煌 + 1 赞一个!

查看全部评分

10 个回复

倒序浏览
成员变量和方法被static修饰后,都是静态的,在内存存在于方法区中。静态成员,静态方法,静态代码块都存在在内存中的独立于栈和堆内存区的“方法区”中。
static{
  b=6;//注意:变量b属于局部变量,初始化值为6,只作用于静态代码块,执行完毕。b就没有作用了。在内存中的“方法区”中的static构造代码块中,出了这个区域,就没用了
  //System.out.println(b);//这里不能直接打印,
  System.out.println("---------");
}

static int b = 9;
这个b和静态代码块中的b没关系。

//由于静态代码块随着类的加载而加载,而且只执行一次,用于给类进行初始化。
回复 使用道具 举报
杨千里 发表于 2012-9-9 04:04
成员变量和方法被static修饰后,都是静态的,在内存存在于方法区中。静态成员,静态方法,静态代码块都存在 ...

局部变量也得先定义啊,如果直接在代码块里写{b=6;}是不能编译的?
回复 使用道具 举报
楼主你的问题正好也以前我也想问的问题哦。呵呵,关于静态代码块的变量赋值问题,你可以和构造代码块结合起来进行参考,两者在变量赋值上存在类似的情况。不过前者是用来给类进行初始化的,而且只运行一次,而后者是给对象进行初始话的,也只是运行一次。
public class Test {
static{
    c=6;
//System.out.println(c)此处如果打印的话就会出现非法向前引用,因为不知道C是什么类型的变量。
//但是前面如果有非静态变量类型修饰的话这里也可也打印。
  }
static int c=4;
static int f=7;
static
{
  f=8;
System.out.println(f);//此处知道f的类型,所以可以打印,值是8。当然前面有非静态变量类型修饰的话就以这里面的为准,它就相当于在栈中重新开辟了一个局部变量,当代码块运行完之后就释放了,这里没有改变相对应的静态成员变量的值。
                       //但是f的值前面没有对应变量类型修饰时,这是就相当于把静态成员变量f的值改变成8
}
{
  int a=4;
  System.out.println(a+"dad");//这里也会出现非法向前引用。
}
int a=2 ;
int b=3;
{
   b=5;
}

{
  m=3;
  System.out.println(m+"....");//这里是可以打印的,因为静态成员变量是随着类的加载就加载进来了。
}
static int m=4;
public static void main(String[] args) {
System.out.println(Test.c);//值是4.
  System.out.println(Test.f);//值是8.
  Test p=new Test();
System.out.println(p.b);//值是5。
System.out.println(p.a);//值是2。
System.out.println(p.m);//值是4。
}
}

回复 使用道具 举报
本帖最后由 吴兵 于 2012-9-9 11:37 编辑

我是这样理解的不知道对不对:
public class Test{

//静态代码块的作用是用来初始化一些变量或对象的,此处的静态代码块作用就是将变量b初始化为6;
static{
  b=6;
  //System.out.println(b);//这里不能直接打印  此处b并没有完成初始化,所以无法打印
  System.out.println("---------");
}
static int a = 5;
static int b = 9;//若改为static int b; 则打印结果为6
static int c;
public static void main(String[] args) {
  System.out.println(Test.b);
}
}
回复 使用道具 举报
何明辉 发表于 2012-9-9 10:58
楼主你的问题正好也以前我也想问的问题哦。呵呵,关于静态代码块的变量赋值问题,你可以和构造代码块结合起 ...

构造代码块那一块我能理解,但是静态成员加载到类中也是有顺序的吧,static int b;它要比static{代码块}先加载进内存,默认初始化0,在执行static{}代码块中的内容,对类中的成员进行初始化,但如果是这样,那么b这个变量就已经在语句中先定义好了,代码块中应该是可以打印b的值的。实际上static{}代码块中是不能引用b的值,这样还是说不通。。。

public class Test{

static{
  b=6;
  //System.out.println(b);//这里不能直接打印  
   System.out.println("---------");
}
static int a = 5;
//static int b=9;这里注释掉,改成下面的
static int b;//若改为static int b; 则打印结果为6
static int c;
public static void main(String[] args) {
  System.out.println(Test.b);
}
}
回复 使用道具 举报
lz啊,这一部分你就从全局变量和局部变量理解就好,
//static int b=9是全局变量
b=6是局部变量
这样就OK了
回复 使用道具 举报
陈俊来 发表于 2012-9-9 15:41
lz啊,这一部分你就从全局变量和局部变量理解就好,
//static int b=9是全局变量
b=6是局部变量

要是按局部变量理解,局部变量要先定义,才能使用,不能直接在代码块里 b=6;除非static int b=9;先加载了,但如果他先加载了,我在代码块里打印一个已经定义并且重新赋值为6是没问题的,但代码块中的b是不能使用的
回复 使用道具 举报
王红潮 发表于 2012-9-9 17:11
要是按局部变量理解,局部变量要先定义,才能使用,不能直接在代码块里 b=6;除非static int b=9;先加载 ...

你可以这样理解
当执行static{b=6;}的时候发现b未定义,于是它就跑到外面看看是否有全局变量,发现有个
static int b=9;原来已经定义了啊,
所以就没有报错,但由于b=6是局部变量所以最后打印的还是9咯
回复 使用道具 举报
陈俊来 发表于 2012-9-9 18:39
你可以这样理解
当执行static{b=6;}的时候发现b未定义,于是它就跑到外面看看是否有全局变量,发现有 ...

已经搞定了,谢谢,程序运行要分为编译和运行两个阶段,一直都陷在运行里了
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马