黑马程序员技术交流社区

标题: 静态代码块,构造代码块,构造函数的执行顺序窥探 [打印本页]

作者: 黑马朱超    时间: 2013-3-7 22:25
标题: 静态代码块,构造代码块,构造函数的执行顺序窥探
本帖最后由 黑马朱超 于 2013-3-12 03:19 编辑
  1. class Person
  2. {
  3.         private static String name = "unknown";//显示初始化变量name
  4.         private int age ;// 私有化变量age
  5.         private static String country = "CN";//静态变量country
  6.         //静态代码块
  7.         static
  8.         {
  9.                 System.out.println("the class"+"is mounting!");
  10.         }
  11.         //构造代码块
  12.         {
  13.                 System.out.println("the object"+" is creating!");
  14.         }
  15.         Person()//构造函数
  16.         {
  17.                 speak();
  18.     }
  19. //构造函数
  20.         Person(String name,int age)//构造函数把属性指向对象
  21.         {
  22.                 this.name =name;
  23.                 this.age= age;
  24.                 speak();
  25.         }
  26. //对对象修改属性
  27.         public void setName(String name)
  28.         {
  29.                 this.name = name;
  30.         }
  31. //打印名称,年龄
  32.         public void speak()
  33.         {
  34.                 System.out.println("name is "+name+";age is"+age);
  35.         }
  36. //打印静态变量country
  37.         public static void showCountry()
  38.         {
  39.                 System.out.println("country is"+country);
  40.         }
  41. }

  42. class PersonDemo2
  43. {
  44.     //主函数所在类中的静态代码块
  45.     static
  46.     {
  47.         System.out.println("the Demo class "+"is mounting!");
  48.     }
  49.         public static void main(String [] args)
  50.         {
  51.         Person.showCountry();//因为showCountry是静态的,可以直接打印;需要加类名
  52.         new Person();//创建Person类匿名对象
  53.                 Person p = new Person("lian",20);//创建Person类对象,创建时赋值
  54.                  p.showCountry();//对象调用静态函数
  55.                 p.setName("lili");//对对象进行重新改名
  56.                 p.speak();//调用speak
  57.         }
  58. }
复制代码

视频听得不大懂,即使懂了也怕记不住;还是码字出来验证下。呵呵
代码运行的顺序:
1)虚拟机加载主函数所在的类[方法区],如果有静态代码块则初始化//the Demo class is mounting!
2)JVM调用主函数【?主函数在内存的存放在哪里?
3)主函数建立变量作为引用句柄p[栈内存]
4)JVM加载类[方法区],加载类中的static成员和方法到方法区
5)对类初始化(执行静态代码块)//the class is mounting!
6)堆内存开辟空间,分配地址,把地址给句柄【?是在对象属性初始化后把地址给句柄还是一分配地址后就给?
7)建立对象的属性name,age[堆内存]
8)将对象的属性默认初始化
9)将对象的属性显示初始化
10)构造代码块初始化//the Object is creating!
11)构造函数初始化(一般函数不初始化,只在调用的时候执行),如构造函数有实参(局部变量)的话,在栈内存中建立变量,通过this引用到对象的属性(成员变量),更改值//name is age is
12)调用一般函数.

问题:
1.主函数先保存在方法区里了再执行么,还是不存直接调用?
2.建立对象的时候引用句柄赋值对象的堆内存的空间地址是什么时候?
3. 数据类型与数组的关系
private static String name = "unknown";// 像unkonwn这字符串的存储不是以数组的形式存成String类型么?如果是的话,怎么不写成 String[] name


作者: HM汪磊    时间: 2013-3-7 23:24
关于第三个问题,不是以数组形式存储的,String s="unknow";
s是存储在栈里
new String("unknow");
s是存储在堆里
关于堆很栈的区别看下这篇文章:http://developer.51cto.com/art/200812/99540.htm
作者: 袁术森    时间: 2013-3-7 23:28
1、static:代表主函数随着类的加载就已经存在了。应该是随着类的加载而加载进方法区。如果没有存储的地方,怎么被jvm调用。
2、Person p=new Person();p.speak();-----new这个关键字 就意味着在堆内存中创建了Person类对象,每个实体在堆内存中都有首地址,并在栈内存main函数执行语句时,将首地址赋值给变量p
3、(搜索到的)一个字符串在 Java 内部是使用 char[] 来表示的,也就是说一个字符串的最大长度是 2147483647,而String[]字符串数组是可以无限大的,直到内存耗尽。
这是我的个人理解,希望对你有所帮助
作者: 0.00    时间: 2013-3-7 23:32
6)堆内存开辟空间,分配地址,把地址给句柄【?是在对象属性初始化后把地址给句柄还是一分配地址后就给?】 一分配就给了地址,第二个问题就是在这给了地址
3.String name=“unknow” 这个是确定了一个具体的属性, 内存开辟空间的时候 已经确定了里面的元素只有一个字符串, 如何 是定义多个字符串时 就需要 String【】name
我是这样理解的 也是初学者,坐等大神! 求分 各种求
作者: 黑马朱超    时间: 2013-3-9 10:59
HM汪磊 发表于 2013-3-7 23:24
关于第三个问题,不是以数组形式存储的,String s="unknow";
s是存储在栈里
new String("unknow");

String s= "unknown"
的顺序:
1.在常量池中搜索是否有字符串"unknown",如果没有就在编译时放入常量池的常量;
2.class文件被加载后,在栈空间建立变量s作为引用句柄
3.对s赋值“”unknown"的地址(对于基本类型应该不会用到常量池,因为基本类型的值就存在栈中,在Java中对基本类型变量的运算、判断以及赋值都是对值的操作,没有对地址操作,例如:int a = 1; int b = 2; a = b; 这是将b的值赋给a,而不是a引用b;)

new String("unknown");
的顺序:
1.在常量池中搜索是否有字符串"unknown",如果没有就在编译时放入常量池的常量;
2.在堆内存开辟空间,建立对象,对对象的属性进行默认初始化name=null;age =0
3.把常量池中的"unknown"赋值给对象的属性(对内存中属性赋值,不是引用地址)
可以参考
http://wenku.baidu.com/view/2e3f652cb4daa58da0114a1a.html
作者: 黑马朱超    时间: 2013-3-9 11:25
袁术森 发表于 2013-3-7 23:28
1、static:代表主函数随着类的加载就已经存在了。应该是随着类的加载而加载进方法区。如果没有存储的地方 ...

对于问题2:
准确点应该是在构造函数初始化之后把对象首地址传给引用变量
对于问题3:private static String name = "unknown";
String类的本质是字符数组char[],其次String类是final的,是不可被继承的,这点可能被大多数人忽略,再次String是特殊的封装类型,使用String时可以直接赋值,也可以用new来创建对象,但是这二者的实现机制是不同的。还有一个String池的概念,Java运行时维护一个String池,池中的String对象不可重复,没有创建,有则作罢。String池不属于堆和栈,而是属于常量池。
"unknown"是个字符串常量,在编译的时候如果常量池中没有,就在常量池中赋值一个;然后把地址传给name(不是直接把值写到栈内存的变量name中,因为String不是基本类型);
http://sarin.iteye.com/blog/603684/
作者: 黑马朱超    时间: 2013-3-9 11:26
0.00 发表于 2013-3-7 23:32
6)堆内存开辟空间,分配地址,把地址给句柄【?是在对象属性初始化后把地址给句柄还是一分配地址后就给?】  ...

看我在帖子中的回复,呵呵




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