黑马程序员技术交流社区

标题: 静态块问题 黑马们来帮我看下啊 [打印本页]

作者: walkonby    时间: 2013-1-20 01:56
标题: 静态块问题 黑马们来帮我看下啊
本帖最后由 张政 于 2013-1-20 22:32 编辑
  1. class Test{
  2.         static{
  3.                 System.out.println("b");
  4.         }
  5.         public static void main(String args[]){
  6.                 new Test1();
  7.                 new Test1();
  8.                 System.out.println(11);
  9.         }
  10.         static{
  11.                 System.out.println("c");
  12.         }
  13. }
  14. class Test1{
  15.         static{
  16.                 System.out.println("a");
  17.         }
  18. }
复制代码
执行结果:
b
c
a
11

看了老师讲的我还不信 又自己写代码试了一下 还真是老师那个结果  
但是这样我就想不通了  我想问的是为什么不输出两次a呢  前面我new 一个对象在堆中出现了一个对象 然后执行静态块输出a 这个我能理解 但是到后面这个对象在堆中开辟的内存不是没人指向吗 应该就被回收了啊  然后下面又继续new 一个对象 应该又执行一次输出a啊  但是结果又不是这样 彻底懵了  求解答啊




作者: 夏振博    时间: 2013-1-20 02:23
本帖最后由 arno942 于 2013-1-20 02:31 编辑

在这个类第一次被调用或实例化的时候就会被执行。
静态代码块只会执行一次,一般会用来初始化一些值,并且在所有对象中全局共享
也就是说:
第一步是类加载,静态块在类加载的时候就执行了,只执行一次,因为不可能进行第二次类加载,
用法:
有些代码需要在类加载时就必须完成的时候,使用静态块。
对静态属性的初始化很复杂时(不是一条语句能完成的时候),使用静态块。

作者: 唐晓    时间: 2013-1-20 08:21
静态代码块只会执行一次,而且比类加载还早,只要调用先执行静态代码块。就算你new多个,加载完一次后就不会再加载了。
作者: 折纸时代    时间: 2013-1-20 09:28
本帖最后由 司懿卓 于 2013-1-20 09:29 编辑

静态成员是类所属的,不会因为对象的消失而回收的.
你创建两次对象,第一次创建时,静态初始化块会先进行初始化,然后才是非初始化块(如果有执行语句的话)和构造器,创建对象.
很显然,上面代码中没有非静态初始化块,也就是多次创建对象,没有显示结果.
代码帮你修改了下,现在第二次创建对象, 是打印 "d" .
  1. class Test{
  2.         static{
  3.                 System.out.println("b");
  4.                System.out.println("c");

  5.         }
  6.         public static void main(String args[]){
  7.                 new Test1();
  8.                 new Test1();
  9.                 System.out.println(11);
  10.         }
  11.         /*static{                                //一个类中,静态初始化块和非静态初始化块最好一样出现一个,.多了无意义.
  12.                 System.out.println("c");
  13.         }*/
  14. }
  15. class Test1{
  16.         static{
  17.                 System.out.println("a");
  18.         }
  19.         {                                         //非静态初始化块是随着对象的创建而执行初始化的.
  20.                   System.out.println("d");  
  21.         }
  22. }
复制代码

作者: 卢浩    时间: 2013-1-20 10:03
你的会不会被回收的疑问我是这么想的哈,既然是静态嘛肯定是随着类的加载而存在的,随着类的消亡而消亡的,他应该是跟类同生共死的,所以不会被回收的,他并不是实例出来的东西,你可以类比下静态变量去理解,大前提都是静态嘛,这也是静态的特点,生命周期过长。执行一次用来初始化的。
作者: 卢浩    时间: 2013-1-20 10:03
你的会不会被回收的疑问我是这么想的哈,既然是静态嘛肯定是随着类的加载而存在的,随着类的消亡而消亡的,他应该是跟类同生共死的,所以不会被回收的,他并不是实例出来的东西,你可以类比下静态变量去理解,大前提都是静态嘛,这也是静态的特点,生命周期过长。执行一次用来初始化的。
作者: 高浩    时间: 2013-1-20 12:34
关于静态的,静态代码块,静态成员,都会随着类的加载而加载上,就是只要编译了该类文件,它里面的静态成员都会先跟着加载,存在内存中,而对象则是当你什么时候调用它的构造函数,它才会在堆内存中开辟一块空间。
作者: walkonby    时间: 2013-1-20 15:30
司懿卓 发表于 2013-1-20 09:28
静态成员是类所属的,不会因为对象的消失而回收的.
你创建两次对象,第一次创建时,静态初始化块会先进行初 ...

他这个类又是在哪里的呢 是堆中还是栈中 或者就是我在本地磁盘上的哪个class文件? 是本地的class文件的话是不是我每执行一次main方法都会重新生成class而执行静态块呢? 还有就是我看到楼下写的 类的消亡  我想问下这个到底是什么时候开始被加载然后又什么时候消亡的呢?还是就是我想的执行一次main就是一次加载 消亡呢?
作者: 折纸时代    时间: 2013-1-20 16:52
本帖最后由 司懿卓 于 2013-1-20 16:55 编辑
张政 发表于 2013-1-20 15:30
他这个类又是在哪里的呢 是堆中还是栈中 或者就是我在本地磁盘上的哪个class文件? 是本地的class文件的 ...

静态成员,就是使用static修饰的成员。非静态成员就是没有static修饰的成员。成员包括成员变量(Field),方法(函数),初始化块,内部类等。
b.静态成员和非静态成员的区别:
静态成员也是类成员,是属于类的。可以通过类名直接调用。非静态成员是属于对象的,必须创建对象后才可以调用。
因为java运行的机制问题,和静态、非静态的区别,所以其运行顺序是有很大的差别的。先浅显说下java运行机制,首先呢,在编译后,运行时,JVM会寻找主方法入口,也就是程序的开始。这时,如果创建对象,创建对象之前,会先加载主方法(main方法)所在的类,因为静态成员都是类所属的。所以,在主类加载后呢,所有的静态成员都会随着加载。这时呢,因为对象还没有创建成功,非静态成员还不存在。比如,我网购买了个手机,但是手机还没到我手上,我怎么去使用呢? 肯定需要等到手机到了后才可以。 这就是java中静态成员不能访问非静态成员的原因。
其实,随着主类的加载,还有一系列的动作在之前操作。那就是,该类的所有父类进行初始化。因为,该类继承了父类,如要需要调用到父类的成员,肯定要知道父类中的情况。这样,该类的最高父类开始进行初始化,然后是其子类,最后才是该类。其实,非静态成员的初始化和静态成员的一样。不过,是需要创建对象后才执行的。而且,初始化块是在构造器之前执行的。
上面有说到成员所属问题,和子父类的先后初始化问题。下面就简单的说下顺序,然后通过代码来表现跟直观。
初始化相关的成员有:
静态初始化块;非静态初始化块;构造器;
静态初始化块是类成员,类加载,就进行初始化操作。
非静态初始化块是对象所属,创建对象,就进行初始化操作。
构造器,通过new来调用构造器创建对象。调用后,是先执行初始化块,然后才是构造器。
  1. class Root
  2. {
  3.          static        //静态初始化块
  4.         {
  5.               System.out.println("Root的静态初始化块");
  6.          }
  7.         {              //非静态初始化块
  8.         System.out.println("Root的普通初始化块");
  9.         }
  10.         public Root()      //构造器
  11.        {
  12.         System.out.println("Root的无参数的构造器");
  13.        }
  14. }
  15. class Mid extends Root
  16. {
  17.      static{
  18.           System.out.println("Mid的静态初始化块");
  19.      }
  20.      {
  21.            System.out.println("Mid的普通初始化块");
  22.       }
  23.       public Mid()
  24.       {
  25.             System.out.println("Mid的无参数的构造器");
  26.        }
  27.        public Mid(String msg)
  28.       {
  29.             //通过this调用同一类中重载的构造器
  30.             this();
  31.             System.out.println("Mid的带参数构造器,其参数值:"
  32.                + msg);
  33.         }
  34. }
  35. class Leaf extends Mid
  36. {
  37.      static{
  38.              System.out.println("Leaf的静态初始化块");
  39.      }
  40.     {
  41.              System.out.println("Leaf的普通初始化块");
  42.      }
  43.      public Leaf()
  44.      {
  45.              //通过super调用父类中有一个字符串参数的构造器
  46.              super("黑马程序员");
  47.              System.out.println("执行Leaf的构造器");
  48.      }
  49. }
  50. public class Test
  51. {
  52.       public static void main(String[] args)
  53.       {
  54.            new Leaf();
  55.            new Leaf();
  56.        }
  57. }
复制代码
上面代码运行结果是:

Root的静态初始化块
Mid的静态初始化块
Leaf的静态初始化块
Root的普通初始化块
Root的无参数的构造器
Mid的普通初始化块
Mid的无参数的构造器
Mid的带参数构造器,其参数值:黑马程序员
Leaf的普通初始化块
执行Leaf的构造器
Root的普通初始化块
Root的无参数的构造器
Mid的普通初始化块
Mid的无参数的构造器
Mid的带参数构造器,其参数值:黑马程序员
Leaf的普通初始化块
执行Leaf的构造器

        上面程序创建了两次对象,但是为什么静态成员只执行了一次呢?
是因为,静态成员是类所属的,随着类的加载而执行。第一次创建对象的时候,就被初始化了。那么第二次创建还有必要再次进行初始化么?完全不用的。其实,它们的运行顺序很简单,清楚了成员所属、和继承、运行机制也就清楚了。
-------------------------------------------------------------------------------------------------
这是我之前的一篇博客,但是感觉很不满意. 就重写了..  你参考下吧.

还有,创建的对象都是在堆中的. 静态的是在方法区中. 只有局部变量等临时数据是在栈中的.
如果还不太懂,就把视频多看几遍吧.

作者: walkonby    时间: 2013-1-20 22:32
司懿卓 发表于 2013-1-20 16:52
静态成员,就是使用static修饰的成员。非静态成员就是没有static修饰的成员。成员包括成员变量(Field) ...

OK  谢了




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