黑马程序员技术交流社区

标题: 静态代码块和静态成员的一点疑惑? [打印本页]

作者: Leo_yeung    时间: 2013-10-12 00:12
标题: 静态代码块和静态成员的一点疑惑?
本帖最后由 Leo_yeung 于 2013-10-15 00:36 编辑
  1. class Demo{
  2.         public static int fun(String s){
  3.                 System.out.println("i="+i+",s="+s);
  4.                 i++;
  5.                 return i;
  6.         }
  7.         static {
  8.                 System.out.println(Demo.i);
  9.                 fun("static code");
  10.                 System.out.println(Demo.i);
  11.                 fun("static code");
  12.         }
  13.         public static int i=10;
  14. }
  15. class A{
  16.         public static void main(String[] args){
  17.                 new Demo();

  18.                
  19.         }
  20. }
复制代码
谁能帮我分析一下,静态代码块,静态成员变量,静态成员函数的加载顺序和执行顺序?
还有一点,就是以上代码中,如若将静态代码块中调用静态成员变量的类名去掉,就会报错,即
  1. System.out.println(Demo.i);
复制代码
编译报错:非法前向引用!不解?为什么方法前没有指定类名调用就不会报错呢?同样是成员变量i的位置在最后?


作者: 张慧    时间: 2013-10-12 01:21
楼主把 public static int i=10;放到静态方法的前面试试,然后在静态代码块中不加类名,就可以看到不会报错。
那说明,静态成员变量和静态代码块的加载顺序是和在类中的位置有关系的。而且你那样打印出来的刚开始的i是0,不也说明这时候静态成员还没有执行那个赋值的操作,使用的是默认值。

至于静态方法,在静态方法中没有写类名也不会报错,那就说明,该方法是静态代码块,静态变量之后加载的。

静态代码块,静态变量这两个都是只加载一次的。静态方法被类调用。
作者: 黄文伯    时间: 2013-10-12 19:06
亲,如问题已解决请将分类的“未解决”改为“已解决”。 以后的问题贴也要及时更改分类哦~
作者: Leo_yeung    时间: 2013-10-12 23:41
张慧 发表于 2013-10-12 01:21
楼主把 public static int i=10;放到静态方法的前面试试,然后在静态代码块中不加类名,就可以看到不会报错 ...

前面两句说的是这个道理,后面两句基本不懂!~~~
我想应该是这样的,静态代码块和静态成员变量在程序中的加载和执行过程是按照程序的顺序执行而进行的。
而之所以静态方法之前不加类名就可以调用,是因为调用方法时,方法要压栈;而此时JVM就会加载方法中用到的变量。而在变量定义之前去直接访问它,此时还未加载;如果在变量前加类名就显式的指向了它的所属,这是JVM就会在程序中寻找并加载这个变量。其实深JVM的底层到底怎样执行的,还是不太清楚,只能这样理解了,不知道对不对?
作者: Leo_yeung    时间: 2013-10-12 23:41
张慧 发表于 2013-10-12 01:21
楼主把 public static int i=10;放到静态方法的前面试试,然后在静态代码块中不加类名,就可以看到不会报错 ...

前面两句说的是这个道理,后面两句基本不懂!~~~
我想应该是这样的,静态代码块和静态成员变量在程序中的加载和执行过程是按照程序的顺序执行而进行的。
而之所以静态方法之前不加类名就可以调用,是因为调用方法时,方法要压栈;而此时JVM就会加载方法中用到的变量。而在变量定义之前去直接访问它,此时还未加载;如果在变量前加类名就显式的指向了它的所属,这是JVM就会在程序中寻找并加载这个变量。其实深JVM的底层到底怎样执行的,还是不太清楚,只能这样理解了,不知道对不对?
作者: Leo_yeung    时间: 2013-10-12 23:42
张慧 发表于 2013-10-12 01:21
楼主把 public static int i=10;放到静态方法的前面试试,然后在静态代码块中不加类名,就可以看到不会报错 ...

前面两句说的是这个道理,后面两句基本不懂!~~~
我想应该是这样的,静态代码块和静态成员变量在程序中的加载和执行过程是按照程序的顺序执行而进行的。
而之所以静态方法之前不加类名就可以调用,是因为调用方法时,方法要压栈;而此时JVM就会加载方法中用到的变量。而在变量定义之前去直接访问它,此时还未加载;如果在变量前加类名就显式的指向了它的所属,这是JVM就会在程序中寻找并加载这个变量。其实深JVM的底层到底怎样执行的,还是不太清楚,只能这样理解了,不知道对不对?
作者: 张慧    时间: 2013-10-13 00:20
Leo_yeung 发表于 2013-10-12 23:41
前面两句说的是这个道理,后面两句基本不懂!~~~
我想应该是这样的,静态代码块和静态成员变量在程序中的 ...

静态变量 和静态代码块  是java虚拟机将类加载到内存中时,就先去加载的  而且只加载一次 ,与new的次数无关。 静态方法中用到的静态变量 应该是在它之间就已经加载了。例如:Demo.fun("test")。首先检查这个内存中是否有这个类,如果没有就先加载Demo这个类到内存中,这个加载的过程中就加载了静态变量 和静态代码块,之后再调用这个静态方法。

具体的他们的在内存空间怎么存储了,我记得视频中有讲到的,:我记不清楚了,就不乱讲啦:'(
作者: 秦大忠    时间: 2013-10-13 21:04
你的这个运行结果i的最初值是0不是10,如果把静态变量的定义放在最开始则则 i 的最初值是10,这个时候也可以去掉Demo.个人觉得静态代码块和静态变量的加载级别是同级的,并且按照顺序执行,所以应该把静态变量放在静态代码块前面,这就是为什么你调用 I 的时候没有Demo.会出现编译失败的原因,因为你加载到这里的时候 i 还没有被加载,静态函数应该是最后加载的,你在Static语句和函数语句的第一行分别输出一个标识的东西就可以看见那个先运行了,至于调用Demo.i 打印那个 i 的值为什么是0我也想知道
作者: Leo_yeung    时间: 2013-10-13 22:43
秦大忠 发表于 2013-10-13 21:04
你的这个运行结果i的最初值是0不是10,如果把静态变量的定义放在最开始则则 i 的最初值是10,这个时候也可 ...

JVM虚拟机底层不知道,但是确定在这里变量前的类名省略和不省略是有区别的。回答你的问题,静态成员变量随着类的加载而加载,首先进行默认初始化,遇到静态代码块执行静态代码,且只执行一次,之后静态成员变量进行显式初始化。
作者: 秦大忠    时间: 2013-10-13 23:37
Leo_yeung 发表于 2013-10-13 22:43
JVM虚拟机底层不知道,但是确定在这里变量前的类名省略和不省略是有区别的。回答你的问题,静态成员变量 ...

静态变量的定义你放在类中最开始的时候,和放在你的程序中的位置,i 的打印结果是不一样的,而且放在最开始的时候,在静态代码块中的 i 的调用可以不需要类名调用,可是在这个程序中却必须要加类名来调用,这是我迷惑的地方,如果你弄懂了这个问题,请联系我Q2363172045,告诉我一声
作者: Joney__    时间: 2013-10-14 17:56
静态代码块的作业是给类初始化,这里我说一下运行顺序,程序先运行静态代码块,在运行构造代码块,在运行构造函数,静态代码块可写一样的,静态代码块一个类只能执行一次
作者: 王飚    时间: 2013-10-14 22:07
加载顺序和执行顺序(权限)是:
静态代码块>构造代码块>构造函数
静态成员变量与静态成员函数位于内存的方法区中的静态方法区中,先于对象存在;
作者: Leo_yeung    时间: 2013-10-15 00:23
王飚 发表于 2013-10-14 22:07
加载顺序和执行顺序(权限)是:
静态代码块>构造代码块>构造函数
静态成员变量与静态成员函数位于内存的方法 ...

好吧,本例中不牵扯对象,因为成员都是静态的,都在方法区中的静态区,所以对象中没有属性……
作者: Leo_yeung    时间: 2013-10-15 00:36
秦大忠 发表于 2013-10-13 23:37
静态变量的定义你放在类中最开始的时候,和放在你的程序中的位置,i 的打印结果是不一样的,而且放在最开 ...

我的理解在帖子中你可以找到的,希望可以帮助你,谢谢参与……结贴了:handshake




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2