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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 张凯 中级黑马   /  2012-7-22 09:04  /  2541 人查看  /  10 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 张凯 于 2012-7-23 07:09 编辑
  1. package ch08;

  2. class MyBook{
  3. MyBook(int maker){
  4. System.out.println("MyBook("+maker+")");
  5. }
  6. void foo(int maker){
  7. System.out.println("foo("+maker+")");
  8. }
  9. }

  10. class MyPackage{
  11. static MyBook b1 = new MyBook(1);
  12. MyPackage(){
  13. System.out.println("MyPackage()");
  14. b2.foo(1);
  15. }
  16. void foo2(int maker){
  17. System.out.println("foo2("+maker+")");
  18. }
  19. static MyBook b2 = new MyBook(2);
  20. }

  21. class MyRoom{
  22. MyBook b3 = new MyBook(3);
  23. static MyBook b4 = new MyBook(4);
  24. MyRoom(){
  25. System.out.println("MyRoom()");
  26. b4.foo(2);
  27. }
  28. void foo3(int maker){
  29. System.out.println("foo3("+maker+")");
  30. }
  31. static MyBook b5 = new MyBook(5);
  32. }
  33. public class StaticIni{
  34. public static void main(String[] args){
  35. System.out.println("Creating new MyRoom() in main");
  36. new MyRoom();
  37. System.out.println("Creating new MyRoom() in main");
  38. new MyRoom();
  39. t2.foo2(1);
  40. t3.foo3(1);
  41. }
  42. static MyPackage t2 = new MyPackage();
  43. static MyRoom t3 = new MyRoom();
  44. }
复制代码
我的疑惑是在这里
class MyPackage{
static MyBook b1 = new MyBook(1);
MyPackage(){
System.out.println("MyPackage()");
b2.foo(1);
}
void foo2(int maker){
System.out.println("foo2("+maker+")");
}
static MyBook b2 = new MyBook(2);
}

b2这个对象为什么先使用b2.foo(1);然后再声明引用static MyBook b2 = new MyBook(2);
这样不是违反了规则了吗?

评分

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

查看全部评分

10 个回复

倒序浏览
没有啊,因为静态显示初始化是优先于构造函数执行的,当MyPackage(){}这个构造函数执行的时候,static MyBook b2 = new MyBook(2); 都已经执行过了。顺便给你说一下,代码执行的顺序,先是静态初始化,然后是静态代码块,然后是普通成员变量的默认初始化,然后是普通成员变量的显式初始化,然后是对对象进行构造代码块初始化,然后再是对象相应的构造函数初始化。所以static MyBook b2 = new MyBook(2); 虽然在下面放,但先执行的。
回复 使用道具 举报
看了这个。我也晕了,求强人回答一下。我步骤这也有错么?

class MyBook{                                                           // //3
MyBook(int maker){
System.out.println("MyBook("+maker+")");
}
void foo(int maker){
System.out.println("foo("+maker+")");              ////4
}
}

class MyPackage{
static MyBook b1 = new MyBook(1);
MyPackage(){
System.out.println("MyPackage()");
b2.foo(1);
}
void foo2(int maker){
System.out.println("foo2("+maker+")");
}
static MyBook b2 = new MyBook(2);            // // 2
}

class MyRoom{
MyBook b3 = new MyBook(3);
static MyBook b4 = new MyBook(4);
MyRoom(){
System.out.println("MyRoom()");
b4.foo(2);
}
void foo3(int maker){
System.out.println("foo3("+maker+")");
}
static MyBook b5 = new MyBook(5);
}
public class StaticIni{
public static void main(String[] args){
System.out.println("Creating new MyRoom() in main");
new MyRoom();
System.out.println("Creating new MyRoom() in main");
new MyRoom();
t2.foo2(1); //                     ///// 1
t3.foo3(1);
}
static MyPackage t2 = new MyPackage();
static MyRoom t3 = new MyRoom();
}
回复 使用道具 举报
feigecal 发表于 2012-7-22 09:33
没有啊,因为静态显示初始化是优先于构造函数执行的,当MyPackage(){}这个构造函数执行的时候,static MyBo ...

能详细讲一下,这个顺序吗?就是先执行哪边的
回复 使用道具 举报
王舜民 发表于 2012-7-22 09:54
能详细讲一下,这个顺序吗?就是先执行哪边的

静态初始化只一次,这一点要注意,下面是顺序
class MyBook
{
MyBook(int maker)
{
  System.out.println("MyBook("+maker+")"); //3   //5   // 11  // 13  //15
}
void foo(int maker)
{
  System.out.println("foo("+maker+")"); //8  //18
}
}
class MyPackage
{
static MyBook b1 = new MyBook(1); //2
MyPackage()
{
  System.out.println("MyPackage()"); //6
  b2.foo(1);                         //7
}
void foo2(int maker)
{
  System.out.println("foo2("+maker+")"); //30
}
static MyBook b2 = new MyBook(2); //4
}
class MyRoom
{
MyBook b3 = new MyBook(3); // 14   //21   //26
static MyBook b4 = new MyBook(4); //10
MyRoom()
{
  System.out.println("MyRoom()"); // 16   //22   //27
  b4.foo(2);                        //17  //23   //28
}
void foo3(int maker)
{
  System.out.println("foo3("+maker+")"); //32
}
static MyBook b5 = new MyBook(5); // 12
}
public class StaticTni
{
public static void main(String[] args)
{
  System.out.println("Creating new MyRoom() in main"); //19
  new MyRoom();                                        //20
  System.out.println("Creating new MyRoom() in main");   //24
  new MyRoom();                                        //25
  t2.foo2(1);                                         //29
  t3.foo3(1);                                        //31
}
static MyPackage t2 = new MyPackage(); // 1
static MyRoom t3 = new MyRoom(); //  9
}
我就纳闷了,不就想看顺序吗,用搞这么多吗,看着太费劲

评分

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

查看全部评分

回复 使用道具 举报
本帖最后由 程潇 于 2012-7-22 12:33 编辑

class MyPackage{
static MyBook b1 = new MyBook(1);
MyPackage(){
System.out.println("MyPackage()");
b2.foo(1);
}
void foo2(int maker){
System.out.println("foo2("+maker+")");
}
static MyBook b2 = new MyBook(2);
}

//在MyPackage类的定义中,虽然形式上是b2.foo(1);这句话在b2声明之前,但是实际上static MyBook b2 = new MyBook(2); 这句话要先于b2.foo(1)执行。
//原因是,这个涉及到了对象初始化过程中的执行顺序
//我们先来分析一下你这个类的构成,包含两个属性b1和b2,一个构造方法MyPackage(),一个成员方法foo2(int maker)
//再来分析一下对象的初始化过程:看看MyPackage t2 = new MyPackage();这句话都做了什么事情
1.因为new用到了MyPackage.class,所以会先找到MyPackage.class文件加载到内存
2.执行该类中的static代码块,这个类中没有,所以此步骤可以忽略
3.在堆内存中开辟空间,分配内存地址给对象
4.在堆内存中建立对象的特有属性,并进行默认初始化。在这里就是对b1和b2进行默认初始化,效果是b1=null; b2=null;
5.对属性进行显式初始化。就是执行类中的初始化动作,static MyBook b1 = new MyBook(1); 和static MyBook b2 = new MyBook(2);
6.对对象进行构造代码块初始化,这个类没有构造代码块,所以此步骤可以忽略
7.对对象进行对应构造函数初始化,就是执行构造方法MyPackage();在执行构造方法的过程中执行了
b2.foo(1);,而b2已经在第5步中进行了初始化,所以这里调用没有任何问题
8.将对象内存地址赋给栈内存中的变量t2


通过以上步骤可以看出,在实际的对象初始化过程中,b2的声明是在b2调用之前的




回复 使用道具 举报
林康春 黑马帝 2012-7-22 11:01:16
7#
代码执行顺序:

     程序加载class文件,加载了这个public class StaticIni 类后,立刻进行静态代码块的部分
static MyPackage t2 = new MyPackage();
static MyRoom t3 = new MyRoom();
先读  static MyPackage t2 = new MyPackage();
加载 MyPackage 这个类,同样的先执行静态代码块一:static MyBook b1 = new MyBook(1); 二:static MyBook b2 = new MyBook

(2);
对一:同样的加载MyBook 这个类,先执行静态代码块,这MyBook 类中没有静态代码块,因此进行实例对象初始化,执行
MyBook(int maker){ System.out.println("MyBook("+maker+")"); }这句,打印出MyBook(1);
对二:因为在一中已经给类MyBook 加载了,因此二的代码直接进行实例对象初始化,打印出MyBook(2)
现在,到了对MyPackage 这个类进行实例对象初始化了,相应的打印出MyPackage(),再执行里面构造函数的下一条语句b2.foo(1);
相应的去调用这个方法,执行MyBook类中的void foo(int maker){System.out.println("foo("+maker+")"); },打印出foo(1);


到此,执行完static MyPackage t2 = new MyPackage(); 后,接桌执行tatic MyRoom t3 = new MyRoom()
先加载MyRoom 这个类,成员变量默认初始化,即MyBook b3=null,然后静态代码的执行 一 :static MyBook b4 = new MyBook(4);

二: static MyBook b5 = new MyBook(5);
对一:因为在上面已经给这个类加载了,同理的直接进行实例对象初始化,打印出MyBook(4)
对二:和上面的一  一样,打印出MyBook(5)
现在,来到了对new MyRoom()实例对象初始化,相应的执行构造函数的语句MyRoom(){ System.out.println("MyRoom()"); b4.foo

(2); },先打印出MyRoom(),再执行里面构造函数的下一条语句b4.foo(2),打印出foo(2)

好了,到此,进入主函数main()里面了,先执行System.out.println("Creating new MyRoom() in main"); ,打印出
Creating new MyRoom() in main
然后执行new MyRoom();
这个类MyRoom已经加载了,因此只执行实例对象初始化,先显示成元变量MyBook b3,即b3=new MyBook (),那这样就要访问了MyBook

这个类,这个类已经加载了,因此只执行实例对象初始化,即执行MyBook(int maker){System.out.println("MyBook("+maker+")");
},打印出Mybook(3)  .再执行new MyRoom()对应的构造函数语句,得到打印出MyRoom(),调用b4.foo(2)语句时,得到打印出foo(2)

继续,执行System.out.println("Creating new MyRoom() in main"); 打印出Creating new MyRoom() in main
继续执行下面的new MyRoom();
这和上面的一样,得到打印的结果: MyBook(3)  MyRoom() foo(2)
最后执行 t2.foo2(1); t3.foo3(1); 这两句
得到打印结果foo2(1)和foo3(1)



回复 使用道具 举报
feigecal 发表于 2012-7-22 10:20
静态初始化只一次,这一点要注意,下面是顺序
class MyBook
{

谢谢。终于看清楚了。你就是按照
“先是静态初始化,然后是静态代码块,然后是普通成员变量的默认初始化,
然后是普通成员变量的显式初始化,然后是对对象进行构造代码块初始化,然后再是对象相应的构造函数初始化。”
一步步慢慢分析的对吧?
我太浮躁了,谢谢!
回复 使用道具 举报
杨朔 中级黑马 2012-7-22 12:19:14
9#
一道简单题,非要弄那么长的代码,一个执行顺序的问题。首先你要了解内存分析。首先,一个程序开始编译时,
1:把该文件的。class文件加载到方法区,此时所有的静态方法和静态常量也加载到方法区,
2:main方法入栈按照顺序执行
具体的没写,你自己多看看吧,要想学这个,就先把你的static学好,还有内存分析
回复 使用道具 举报
feigecal 发表于 2012-7-22 09:33
没有啊,因为静态显示初始化是优先于构造函数执行的,当MyPackage(){}这个构造函数执行的时候,static MyBo ...

原来静态显示初始化是优先于构造函数执行的,谢谢了。
回复 使用道具 举报
static MyBook b2 = new MyBook(2);  这个静态方法在其他代码执行前已经加载执行了,和在程序中出现的顺序没关系
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马