黑马程序员技术交流社区

标题: 关于毕老师视频中的错误(?) [打印本页]

作者: 王亚东    时间: 2013-3-8 15:24
标题: 关于毕老师视频中的错误(?)
看到老师视频分析Person p = new Person("zhangsan",20)的执行过程,视频中说是最后才把内存地址赋值给p变量,但是通过对name的显式初始化,可以在构造代码块中打印出p的值,和最后p的值是一样的,所以我感觉是在堆内存中分配地址之后,建立对象属性之前就把内存地址赋值给了p
  1. public class Person {
  2.         private static String staticName = "aa";
  3.         private String name=this.toString();
  4.         private int age;
  5.        
  6.         static {
  7.                 System.out.println("静态代码块:\tstaticName = "+staticName);
  8.         }
  9.         {
  10.                 System.out.println("构造代码块:\t\tname = "+this.name+",age = "+this.age);
  11.         }
  12.         public Person() {
  13.                 System.out.println("自定义无参构造方法");
  14.         }
  15.         public Person(String name,int age){
  16.                 this.name = name;
  17.                 this.age = age;
  18.                 System.out.println("带参数的构造方法:\tname = "+this.name+",age = "+this.age);
  19.         }
  20.         public static void main(String[] args) {
  21.                 Person p = new Person("zhangsan",20);
  22.                 System.out.println(p);
  23.         }
  24. }
  25. /*
  26. Person p = new Person("zhangsan",20);执行顺序:
  27. 1、在栈内存 变量 p;
  28. 2、new关键字用到了Person.class,jvm找到Person.class文件并加载到内存;
  29. 3、在加载Person.class的时候,会执行其中的静态代码块(建立静态属性和方法),按顺序执行,开辟方法区内存;

  30. 4、在堆内存中开辟空间,分配地址,并把地址赋值给p;
  31. 5、在堆内存中建立对象的特有属性,并默认初始化;
  32. 6、对属性进行显式初始化;
  33. 7、对对象进行构造代码块初始化;
  34. 8、对对象进行相应构造方法的初始化;
  35. */
复制代码

作者: 谢洋    时间: 2013-3-9 10:47
我记得毕老师说过:构造代码块是给所有对象初始化,先于构造函数执行
那么如要对象进行构造初始化,那就得先开一个空间出来(空间肯是有地址的嘛),然后再往这个空间做一些初始化动作吧
但是从你的码代中,我真看不出是:"所以我感觉是在堆内存中分配地址之后,建立对象属性之前就把内存地址赋值给了p”
如果真是这样,好像有点不符合逻辑。
作者: 张宁    时间: 2013-3-9 11:33
不对,你Person p = new Person ("zhangsan",20);的执行顺序是,, 现在对内存中开辟一个person对象的空间,name 先默认初始化为null,然后进行显示初始话,然后对对象进行构造函数初始化,把 zhangsan 和 20  赋给了 name 和 age。最后完成这一系列动作之后,才把新生成的这个对象的地址赋值给p。
作者: 黑马朱超    时间: 2013-3-9 12:27
本帖最后由 黑马朱超 于 2013-3-9 12:28 编辑

我们说这个之前先说说显示初始化吧
private static String name = "aa";//显示初始化
1.javac.exe在编译XX.java文件的时候,发现文件中有"aa"的字符串常量,它查询常量池(一种内存空间)中是否有这样的常量,如果无就写入常量池
2.java.exe在运行类文件时,加载Person类;
3.把Static 静态成员都存储在静态区;在静态区内建立类String的same变量作为引用句柄,指向"aa";
Person p = new Person("zhangsan",20)//建立Person的对象
1.在编译java文件时,把"zhangsan",20都放入常量池
2.运行该语句时候,在栈内存中建立类Person的变量P作为引用句柄
3.用new在堆内存开辟空间建立类的对象,对象的属性进行默认初始化name =null,age =0;
4.对类的属性进行显示初始化;把"aa"赋值为name;//name ="aa"
5.构造代码块初始化
6.构造函数初始化,对于Private 变量,通过this.变量 把"zhangsan"和20分别赋值给name ,age//name ="zhangsan",age = 20;
7.把对象的地址赋值给引用句柄
  1. class Person
  2. {
  3.         private static String name = "unknown";//显示初始化变量name
  4.         private int age =-1 ;// 私有化变量age
  5.         //构造代码块
  6.         {
  7.                 System.out.println("the object"+" is creating!");
  8.         }
  9.         Person()//构造函数
  10.         {
  11.           speak();
  12.     }
  13. //构造函数
  14.         Person(String name,int age)//构造函数把属性指向对象
  15.         {
  16.                          this.name =name;
  17.                          this.age =age;
  18.                          speak();
  19.         }
  20. //对对象修改属性
  21.         public void setName(String name)
  22.         {
  23.                 this.name = name;
  24.         }
  25. //打印名称,年龄
  26.         public void speak()
  27.         {
  28.                 System.out.println("name is "+name+";age is"+age);
  29.         }
  30. }

  31. class PersonDemo2
  32. {
  33.     //主函数所在类中的静态代码块
  34.     static
  35.     {
  36.         System.out.println("the Demo class "+"is mounting!");
  37.     }
  38.         public static void main(String [] args)
  39.         {
  40.                 new Person();//创建Person类匿名对象,显示初始化name= "unknown" age =-1;
  41.                 new Person("zhangsan",10);//显示初始化后构造函数初始化时赋值 name = "zhangsan" age = 10
  42.                 Person p = new Person("lian",20);//创建Person类对象,构造函数初始化时赋值 name ="lian",age =20
  43.                 p.setName("lili");//对对象进行重新改名,name = "lili"
  44.                 p.speak();//调用speak一般函数时赋值
  45.         }
  46. }
复制代码



作者: 黑马朱超    时间: 2013-3-9 12:29
看看四楼
作者: 王亚东    时间: 2013-3-9 15:27
谢洋 发表于 2013-3-9 10:47
我记得毕老师说过:构造代码块是给所有对象初始化,先于构造函数执行
那么如要对象进行构造初 ...

构造代码块比构造方法先执行是没错的吧,显然在执行构造代码块之前,属性的显式初始化已执行过了,是通过
name=this.toString();来初始化的,而这时this就是代表当前的对象(其实是地址值),说明在显式初始化之前this(p)就有了值了,所以应该是分配地址后就把地址赋值给p。
比如,我刚买了房子,就可以把地址给你,而房子里的家具什么可以在告诉你了地址后去置办
作者: 王军行    时间: 2013-3-9 16:26
本帖最后由 王军行 于 2013-3-9 16:30 编辑

我记得毕老师在画图讲解的时候说过内存空间先分配的啊,毕老师还说过他画的顺序是错误的应该先静态初始化完之后就有地址了然后把地址值给引用的然后再往里面装东西。。。毕老师视频都说过
黑马程序员_毕向东_Java基础视频教程第06天-07-面向对象(对象的初始化过程) 里面有啊第八分五十秒他说分配地址动作又忘画了应该先画。前面视频题过


作者: 谢洋    时间: 2013-3-9 16:35
王亚东 发表于 2013-3-9 15:27
构造代码块比构造方法先执行是没错的吧,显然在执行构造代码块之前,属性的显式初始化已执行过了,是通过 ...

”所以应该是分配地址后就把地址赋值给p。“我上面并不否定这一句,
但我否你的是一这个句:"建立对象属性之前就把内存地址赋值给了p”

作者: 黑马朱超    时间: 2013-3-9 16:57
呵呵,求高人普及知识
作者: 王亚东    时间: 2013-3-9 20:00
谢洋 发表于 2013-3-9 16:35
”所以应该是分配地址后就把地址赋值给p。“我上面并不否定这一句,
但我否你的是一这个句:"建立对象属性 ...

呵呵,要说语文语法的话,“分配地址”和“把地址赋值给p”是用“就”连起来的,那么就是说这两步是连续的,一分配地址,就给p赋值。。。
作者: 牵强的笑掩饰内    时间: 2013-3-27 20:06
学长好厉害,学java多长时间了
作者: 胡军    时间: 2013-3-28 08:46
楼主,你把我搞糊涂了,到底是你对了,还是毕老师对了?
可是我感觉你的代码并不能反驳毕老师啊
首先,显示初始化的时候,给name赋值是this.toString(),也就是当前对象的引用,但是this指的就是当前对象的引用,当计算机在内存中为对象开辟内存空间时,肯定已经分配了内存地址,也就是this已经有了指向,打印输出的时候肯定有值了。但这时计算机并不一定把堆内存中对象的引用赋给了栈内存中的变量p啊。




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