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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 张向辉 于 2013-1-19 12:35 编辑

class Person
{
        Person()
        {
                System.out.println("-----------构造函数------------");
        }

        {
                System.out.println("-----------构造代码块------------");
        }
        static
                {
                        System.out.println("-----------静态代码块------------");
                }
}

class  Test2
{
        public static void main(String[] args)
        {
                Person p1 = new Person();
                Person p2 = new Person();
        }
}

运行结果:
-------------------静态代码快-------------------
-------------------构造代码快-------------------
-------------------构造函数----------------------
-------------------构造代码快-------------------
-------------------构造函数----------------------

以下是我的理解:
1.静态代码块和构造代码的作用范围是整个类,用于初始化一个类中的共性属性,构造函数的作用范围是某一个特定的类,用于初始化一个类中的特有属性;
2.静态代码块是随着类的加载而加载,构造代码块和构造函数是随着对象的创建而加载,因此它们的加载顺序是:静态代码块、构造代码块、构造函数;
3.静态代码块随着类的加载而加载但仅加载一次,而构造代码块与构造函数是随着对象的加载而加载,每当new一个对象时就会加载一次。

可以如上理解静态代码块与构造代块的特点及加载顺序吗?或者还有其他的一些特点,请高手指点。谢谢!

评分

参与人数 1技术分 +1 收起 理由
高境 + 1 神马都是浮云

查看全部评分

5 个回复

倒序浏览
静态代码块是在new对象后自动加载,而且只加载一次。运行完静态代码块后然后才运行new之后的构造函数。
构造代码块是new加载完后首先执行,早于构造函数。
所以 Person p1 = new Person();后运行顺序是静态代码块->构造代码块->构造函数.
Person p2 = new Person();由于静态代码块已经被加载,只能运行一次,所以运行后顺序是构造代码块->构造函数.

评分

参与人数 1技术分 +1 收起 理由
高境 + 1 鼓励一个!最好带上详细的代码~~.

查看全部评分

回复 使用道具 举报
关于静态的东西,都是随着类文件的加载而加载出来,所以它应该首当其冲的。
回复 使用道具 举报
其实这类的问题,最好的方法就是自己写一下.
把可以有执行语句的地方写上打印语句,打印字符串用以标记分类.
  1. class Root
  2. {
  3.         static{
  4.                 System.out.println("Root的静态初始化块");
  5.         }
  6.         {
  7.                 System.out.println("Root的普通初始化块");
  8.         }
  9.         public Root()
  10.         {
  11.                 System.out.println("Root的无参数的构造器");
  12.         }
  13. }
  14. class Mid extends Root
  15. {
  16.         static{
  17.                 System.out.println("Mid的静态初始化块");
  18.         }
  19.         {
  20.                 System.out.println("Mid的普通初始化块");
  21.         }
  22.         public Mid()
  23.         {
  24.                 System.out.println("Mid的无参数的构造器");
  25.         }
  26.         public Mid(String msg)
  27.         {
  28.                 //通过this调用同一类中重载的构造器
  29.                 this();
  30.                 System.out.println("Mid的带参数构造器,其参数值:"
  31.                         + msg);
  32.         }
  33. }
  34. class Leaf extends Mid
  35. {
  36.         static{
  37.                 System.out.println("Leaf的静态初始化块");
  38.         }
  39.         {
  40.                 System.out.println("Leaf的普通初始化块");
  41.         }       
  42.         public Leaf()
  43.         {
  44.                 //通过super调用父类中有一个字符串参数的构造器
  45.                 super("疯狂Java讲义");
  46.                 System.out.println("执行Leaf的构造器");
  47.         }
  48. }
  49. public class Test
  50. {
  51.         public static void main(String[] args)
  52.         {
  53.                 new Leaf();
  54.                 new Leaf();
  55.         }
  56. }

复制代码
问题点:
1. 静态初始化块
2.非静态初始化块
3. 构造器
所谓静态:
就是在类加载时,就随着类也加载了. 或者说,静态的成员都是类成员,随着类的加载而加载.
不像非静态成员变量,必须要创建对象.

那它们的运行顺序呢?
其实,上面的代码可以很清楚的看到结果.
1. 首先,通过new来创建对象,在此之前呢.会先初始化该类,又因为,java在加载某类时,会把该类的所以父类(至Object)都进行初始化操作.
2. 因为,static修饰的成员都是类成员,会随着类的加载而执行. 所以,会从最高父类执行静态初始化块,然后是其子类.就是把静态初始化块从上到下执行个遍.
3. 然后对象被创建了, 因为java的运行机制,所以还得再重复刚才的动作,不过这次是非静态初始化块和构造器.
4.非静态初始化块优先于该类构造器,但又因是父类,所以两者都优先于其子类执行. 过程就是,最高父类的非静态代码块 --> 构造器--> 其子类非静态代码块 --> 构造器
  最后 执行到最底层的子类.
5. 又通过new创建了个对象,因为静态的成员已经存在,所以无须再次创建.只是再次执行非静态便可.把从第3步到 第4步重复一遍..

至此,整个程序运行结束!

评分

参与人数 1技术分 +1 收起 理由
Rancho_Gump + 1 赞一个!

查看全部评分

回复 使用道具 举报
现在,这个代码一共用了3片, 内存空间!  
分别是 : 堆  、栈 、 方法区! 对不对, 而方法区, 又分为, 普通方法区 和静态方法区!

而加载的顺序是先加载, 方法区,在加载堆, 随着对象对函数的引用才使用到栈。

主函数,在实例化对象的时候, 先加载类中的静态成员变量,方法 静态方法, 静态代码块 放到方法区中。
而静态代码块,是随着类的加载而加载,而且是放到方法区的所以,只加载了一次。 (方法区的类只能加载一次)

而构造代码块和构造函数 是随着对象的的加载而加载。 先加载,构造代码块,最后才 调用构造函数。返回到,主函数中的 Person 变量里。

为什么先加载了构造代码块而后加载了 构造函数,构造代码块是加载对象的时候,起一个初始化的作用
如果,先加载构造函数,这个对象就返回了呀!{:soso_e127:}
而你又有new 了一次,所以,堆内存中,又开辟了一块空间,来加载新的对象,而构造代码块和构造函数 是随着对象的的加载。所以,构造代码块
和 构造函数又加载了一次!
所你 你写的代码加载顺序就是,  静态代码块      构造代码块     构造函数       构造代码块          构造函数     

评分

参与人数 1技术分 +1 收起 理由
Rancho_Gump + 1 赞一个!

查看全部评分

回复 使用道具 举报
       当父类与子类都有静态代码块和构造函数的时候,执行顺序如下:
       父类静态代码块 > 子类静态代码块 java虚拟机加载类时,就会执行该块代码。

       父类构造函数 > 子类构造函数 (先有父亲,后有孩子)

       如果是多级继承关系的话,高层的父类首先执行,然后依次递减

    总结:静态优先执行,父类优先于子类执行
                静态代码块是在JVM加载类的时候执行的,而且静态代码块执行且仅执行一次

评分

参与人数 1黑马币 +9 收起 理由
Rancho_Gump + 9 赞一个!

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马