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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© rosv 中级黑马   /  2013-5-11 19:09  /  2643 人查看  /  17 人回复  /   1 人收藏 转载请遵从CC协议 禁止商业使用本文

//谁能解释下public String name = "heima"; 在位置1和位置2的区别?
public class Person
{
    //位置1
    {
        name = "java";
    }
    //位置2
}

评分

参与人数 1技术分 +1 收起 理由
曹睿翔 + 1 新人鼓励!

查看全部评分

17 个回复

倒序浏览
没有区别。
Person p = new Person();
当创建这个Person类的对象的时候。
Person类对象初始化的过程是:
1,加载Person.class类文件。
2,执行static静态代码块。
3,开辟内存空间,分配内存地址。
4,创建对象特有的属性,执行默认初始化。
5,对对象特有属性执行显示初始化。
6,执行构造代码块。
7,执行构造函数。
8,new表达式返回对象的引用,并赋值给p变量。
位置1和位置2都是在第5阶段赋值为"heima",然后被第6阶段的"java"覆盖。
最后name的值都是"java".
回复 使用道具 举报
基本没啥区别吧 应该是系统在内存中分配存储空间的方式不一样吧  同样坐等大神回复
回复 使用道具 举报
王溢君 来自手机 中级黑马 2013-5-11 19:30:39
板凳
没有区别,新建对象时都会被构造代码块初始化。就是为name
回复 使用道具 举报
恩对。没啥区别。除非你上面和下面都放输出语句。而输出语句是要放在方法里的。外面就只能放属性了。属性不都是随着方法调用而加载?而你的构造代码块放中间貌似也没什么影响吧?
回复 使用道具 举报
没什么区别,都在一个类里。
回复 使用道具 举报
没有什么大的区别
回复 使用道具 举报
没有区别!
{
         name = "java";
     }
上面的代码块为构造函数代码块,作用是给给对象进行初始化。
public String name = "heima"; 为显示初始化,
实体生成后,先是默认初始化(name=null,)后是显示初始化(如String name "heima";)再是构造函数代码块被执行(  name = "java";
),给对象初始化。
所以放在位置1和位置2是没有区别的!
回复 使用道具 举报
没区别,因为那个构造代码块是给所有对象初始化的,构造函数是给对应对象初始化的,在加载的时候是构造代码块优先于构造函数的,所以放哪都一样
回复 使用道具 举报
头像换来换去,每个正型
回复 使用道具 举报
本帖最后由 Neverbelazy 于 2013-5-12 20:41 编辑

1. String str="str"; 看做是两个过程 1). 声明 String str; 2). {str="str"};
2. 在类中,单纯的为变量的引用赋值,是可以先赋予,再在后面声明这个引用的 (c.)
3. 代码执行有先后顺序(a. ; b.), 而且不可以在一个变量的引用没有申明前去用这个引用(d. ; e.)

  1. public class OrderTest {
  2.         String strBefore="strBeforeInitial";//在代码块前定义一个strBefore
  3.         {
  4.                 strBefore="strBeforeCovered"; //在代码块中覆盖
  5.                 strAfter="strAfterCovered";//在代码块中覆盖
  6.                 strCovered="Null covered?Yes!";
  7.                 //System.out.println(strBefore); //d.词句通过编译
  8.                 //System.out.println(strAfter);  //e.词句没有通过编译
  9.         }
  10.         String strAfter="strAfterInitial";//在代码块后定义一个strAfter
  11.         String strCovered;
  12.         {
  13.                 System.out.println("strBefore: "+"Which?  "+strBefore+" is printed.");//a.strBeforeCovered
  14.                 System.out.println("strAfter: "+"Which?  "+strAfter+" is printed"); //b.strAfterInitial
  15.                 System.out.println("strCovered: "+"Which?  "+strCovered+" is printed"); //c.Null covered?Yes!
  16.         }
  17.         public static void main(String[] args) {
  18.                 new OrderTest(); //查看打印结果
  19.         }
  20. }
复制代码
回复 使用道具 举报
rosv 中级黑马 2013-5-12 10:16:39
12#
曹睿翔 发表于 2013-5-12 09:33
头像换来换去,每个正型

:L这个可以商量的。。
回复 使用道具 举报
rosv 中级黑马 2013-5-12 11:38:32
13#
Neverbelazy 发表于 2013-5-12 10:02
1. String str="str"; 看做是两个过程 1). 声明 String str; 2). {str="str"};
2. 在类中,单纯的为变量的 ...

实例变量和初始化块是谁在前谁先执行,后者覆盖前者的值,实例变量和初始化块的代码都会提取到构造函数中执行,详情请看javap的反编译代码

Compiled from "OrderTest.java"
public class OrderTest {
  java.lang.String strBefore;

  java.lang.String strAfter;

  java.lang.String strCovered;

  public OrderTest();
    Code:
       0: aload_0      
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0      
       5: ldc           #2                  // String strBeforeInitial
       7: putfield      #3                  // Field strBefore:Ljava/lang/String;
      10: aload_0      
      11: ldc           #4                  // String strBeforeCovered
      13: putfield      #3                  // Field strBefore:Ljava/lang/String;
      16: aload_0      
      17: ldc           #5                  // String strAfterCovered
      19: putfield      #6                  // Field strAfter:Ljava/lang/String;
      22: aload_0      
      23: ldc           #7                  // String Null covered?Yes!
      25: putfield      #8                  // Field strCovered:Ljava/lang/String;
      28: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      31: aload_0      
      32: getfield      #3                  // Field strBefore:Ljava/lang/String;
      35: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      38: aload_0      
      39: ldc           #11                 // String strAfterInitial
      41: putfield      #6                  // Field strAfter:Ljava/lang/String;
      44: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      47: new           #12                 // class java/lang/StringBuilder
      50: dup           
      51: invokespecial #13                 // Method java/lang/StringBuilder."<init>":()V
      54: ldc           #14                 // String strBefore: Which?  
      56: invokevirtual #15                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      59: aload_0      
      60: getfield      #3                  // Field strBefore:Ljava/lang/String;
      63: invokevirtual #15                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      66: ldc           #16                 // String  is printed.
      68: invokevirtual #15                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      71: invokevirtual #17                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      74: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      77: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
      80: new           #12                 // class java/lang/StringBuilder
      83: dup           
      84: invokespecial #13                 // Method java/lang/StringBuilder."<init>":()V
      87: ldc           #18                 // String strAfter: Which?  
      89: invokevirtual #15                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      92: aload_0      
      93: getfield      #6                  // Field strAfter:Ljava/lang/String;
      96: invokevirtual #15                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      99: ldc           #19                 // String  is printed
     101: invokevirtual #15                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     104: invokevirtual #17                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     107: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     110: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
     113: new           #12                 // class java/lang/StringBuilder
     116: dup           
     117: invokespecial #13                 // Method java/lang/StringBuilder."<init>":()V
     120: ldc           #18                 // String strAfter: Which?  
     122: invokevirtual #15                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     125: aload_0      
     126: getfield      #6                  // Field strAfter:Ljava/lang/String;
     129: invokevirtual #15                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     132: ldc           #19                 // String  is printed
     134: invokevirtual #15                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
     137: invokevirtual #17                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
     140: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     143: return        

  public static void main(java.lang.String[]);
    Code:
       0: new           #20                 // class OrderTest
       3: dup           
       4: invokespecial #21                 // Method "<init>":()V
       7: pop           
       8: return        
}
回复 使用道具 举报
rosv 中级黑马 2013-5-12 11:40:07
14#
类的初始化
Person p = new Person();
Person类对象初始化的过程是:
1、会把上面的代码分成两句执行,Person p;p= new Person();
2、当执行到Person p;时,虚拟机会调用系统类加载器加载Person.class文件到内存中,并验证、准备、解析、Person.class文件;
3、接着在对内存中开辟空间,分配内存地址,用默认值初始化成员变量(数组一旦初始化必须有值,引用类型为null,浮点数值为0.0布尔类型为false,定点类型为0char类型为\u0000)
4、当执行p=new Person()时;,在栈内存中为p开辟空间分配内存地址
5、先调用静态初始化语句(若静态代码块和静态成员变量上都有对同一个变量进行初始化则后者覆盖前者的值);
6、接着执行非静态初始化语句(若构造代码块和成员变量上都有对一个变量的初始化则后者覆盖前者);
7、然后执行对应构造方法里面的语句,最后将内存地址付给栈内存中的p变量。(这里未提到成员函数,只有用到才会初始化且成员函数存放在方法区中)。
类只有在首次主动调用才会初始化
类或接口只有在以下情况下会初始化
1)、创建类的实例;如用new
2)、使用反射、反序列化创建实例
3)、调用类的静态方法;
4)、访问静态变量,或为其赋值
5)、初始化某个子类
6)、直接运行如Java 类名
注意:宏替换不会初始化

点评

赞,总结的很详细!  发表于 2013-5-12 20:35
回复 使用道具 举报
本帖最后由 Neverbelazy 于 2013-5-12 20:33 编辑
rosv 发表于 2013-5-12 11:38
实例变量和初始化块是谁在前谁先执行,后者覆盖前者的值,实例变量和初始化块的代码都会提取到构造函数中 ...

是啊 我觉得你说的和我说的 不矛盾啊  我的意思是
String str="str"; 等价于 String str; + {str="str";}
而代码块是按顺序执行的
  1. class Test{
  2.       {str="str1";}
  3.        String str="str";
  4. }
复制代码
上面一段代码等价于
  1. class Test{
  2.        {str="str1;}
  3.        String str;
  4.        {str="str";}
  5. }
复制代码
所以输出结果是 String str 最后的值还是 "str"

我回复你的意思就是说,如果 在1 位置输出  "java"; 如果在2 位置 输出 "heima"
回复 使用道具 举报

如果帖子没有问题了  那么把帖子的类型改为 “已解决”,  如果不会改   点自己的帖子下面有个编辑,然后改帖子的类型就好了
再不注意结贴,技术分撤销
回复 使用道具 举报
本帖最后由 xuemeng 于 2013-5-14 20:31 编辑

哈!!
楼主, 我懂你的意思了!!
其实你所说位置是有关系的, 这个涉及初始化对象的顺序
new对象时, 会先加载这个对象的类, 当这个类被加载时, 首先为静态属性赋值为默认值,  然后调用静态显示初始化语句和静态代码块中的代码, 它们的顺序是按从上到下的顺序执行; 然后为实例属性赋值为默认值, 然后再调用实例显示初始化语句和实例块, 它们二者也是按从上到下的顺序执行的, 最后执行构造器里面的代码.  如下面验证代码:
class Person {
        Person() {
                System.out.println("构造器");
        }

        P p1 = new P("实例属性p1");

        {
                System.out.println("构造代码块1");
        }

        {
                System.out.println("构造代码块2");
        }
        
        P p2 = new P("实例属性p2");

        static P p3 = new P("静态属性p1");

        static {
                System.out.println("静态初始化块1");
        }

        static {

                System.out.println("静态初始化块2");
        }

        static P p4 = new P("静态属性p2");
}

class P {
        P(String p) {
                System.out.println(p);
        }
}

class Demo {
        public static void main(String[] args) {
                new Person();
        }
}

关于你的代码, 因为实例块(构造代码块) 和显示初始化属性的执行顺序是平级的, 所以他们执行的顺序是按从上到小的顺序执行的, 所以你的代码 public String name ="heima"   这个代码写在1位置和2位置有很大的区别,:
如果写在1的位置, 那么当创建对象, 打印这个属性时, 那么打印的值是java,  因为程序首先给name赋值为 heima, 然后接着有执行构造代码快中的赋值,那么name的值就变成那个了java,
如果写在2的位置,那么当创建对象时  ,首先是执行构造代码块中的代码, name的被赋值为java, 然后接着执行 public String name = "heima";,name被赋值为heima, 所以这个时候如果打印属性的值的话, 那么打印结果是heima
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马