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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© Leo_yeung 中级黑马   /  2013-10-12 00:12  /  2376 人查看  /  13 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 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的位置在最后?

评分

参与人数 1技术分 +2 收起 理由
黄文伯 + 2 多多加油哈!

查看全部评分

13 个回复

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

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

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

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

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

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

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

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

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

静态变量的定义你放在类中最开始的时候,和放在你的程序中的位置,i 的打印结果是不一样的,而且放在最开始的时候,在静态代码块中的 i 的调用可以不需要类名调用,可是在这个程序中却必须要加类名来调用,这是我迷惑的地方,如果你弄懂了这个问题,请联系我Q2363172045,告诉我一声
回复 使用道具 举报
静态代码块的作业是给类初始化,这里我说一下运行顺序,程序先运行静态代码块,在运行构造代码块,在运行构造函数,静态代码块可写一样的,静态代码块一个类只能执行一次

评分

参与人数 1技术分 +1 收起 理由
黄文伯 + 1

查看全部评分

回复 使用道具 举报
王飚 中级黑马 2013-10-14 22:07:13
12#
加载顺序和执行顺序(权限)是:
静态代码块>构造代码块>构造函数
静态成员变量与静态成员函数位于内存的方法区中的静态方法区中,先于对象存在;
回复 使用道具 举报
王飚 发表于 2013-10-14 22:07
加载顺序和执行顺序(权限)是:
静态代码块>构造代码块>构造函数
静态成员变量与静态成员函数位于内存的方法 ...

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

我的理解在帖子中你可以找到的,希望可以帮助你,谢谢参与……结贴了:handshake
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马