【纯干货】构造方法赋值与直接给成员变量赋值的区别

Hello,大家好。
有段时间不见了,最近这阵子有点忙。
我java已经进入复习阶段,所以最近更新频率会高一些。
然后抽出其余的时间去学Android开发和高并发技术。


我想先说几句题外话,java是解释型语言,我们平常编写的java代码编译后会编译成class文件,然后class文件会被JVM虚拟机解释成机器可以识别的二进制数据然后运行。
所以,不管你的java代码写的到底多么的妖魔鬼怪,JVM只认class文件,所以,最终到底程序是怎么运行的,或者研究一些原理,得看class,得学JVM。
其实这就是分层思想,把代码分层,层层封装。


下面是我的研究代码:

class A{
     

   private String msg="尘封已久的恨意";//直接给成员变量赋值

//   public A(String msg){//构造方法赋值
//
//       this.msg=msg;
//   }


    {
     //构造块赋值

        msg="打扫房间哦i啊但是金佛IP圣诞节发票收据阿萨PDF觉得撒泼覅静安寺粕发酵埃斯珀附件";

    }

   public String getMsg(){
     

       return this.msg;
   }
}


public class Main  {
     

     public static void main(String[] args) {
     

       A a=new A();

         System.out.println(a.getMsg());
     }
}

好的这里,我也不卖关子,直接说结论。
不管你是在构造块里对成员变量赋值还是直接给成员变量赋值,程序运行后,赋值的语句都被还原到了构造方法里。

也就是说,你给成员变量赋值的办法只有构造方法一种。

以下是证据:

 <init>()V
   L0
    LINENUMBER 4 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
   L1
    LINENUMBER 6 L1
    ALOAD 0
    LDC "\u5c18\u5c01\u5df2\u4e45\u7684\u6068\u610f"
    PUTFIELD com/myjava/A.msg : Ljava/lang/String;
   L2
    LINENUMBER 16 L2
    ALOAD 0
    LDC "\u6253\u626b\u623f\u95f4\u54e6i\u554a\u4f46\u662f\u91d1\u4f5bIP\u5723\u8bde\u8282\u53d1\u7968\u6536\u636e\u963f\u8428PDF\u89c9\u5f97\u6492\u6cfc\u8985\u9759\u5b89\u5bfa\u7c95\u53d1\u9175\u57c3\u65af\u73c0\u9644\u4ef6"
    PUTFIELD com/myjava/A.msg : Ljava/lang/String;
   L3
    LINENUMBER 18 L3
    RETURN
   L4
    LOCALVARIABLE this Lcom/myjava/A; L0 L4 0
    MAXSTACK = 2
    MAXLOCALS = 1

这个是字节码中的构造方法。
你可以把里面的Unicode编码转成字符串看看.
你赋值的语句最终都被还原到构造方法里了。


但是这里有一个先后顺序

    {
     

        msg="打扫房间哦i啊但是金佛IP圣诞节发票收据阿萨PDF觉得撒泼覅静安寺粕发酵埃斯珀附件";

    }
 
   private String msg="尘封已久的恨意";

z这一次构造块赋值在前,直接赋值在后。

把它俩颠倒一下赋值的顺序,对应着在字节码中的构造方法里,顺序也被颠倒了。

字节码(构造方法):

<init>()V
   L0
    LINENUMBER 4 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
   L1
    LINENUMBER 8 L1
    ALOAD 0
    LDC "\u6253\u626b\u623f\u95f4\u54e6i\u554a\u4f46\u662f\u91d1\u4f5bIP\u5723\u8bde\u8282\u53d1\u7968\u6536\u636e\u963f\u8428PDF\u89c9\u5f97\u6492\u6cfc\u8985\u9759\u5b89\u5bfa\u7c95\u53d1\u9175\u57c3\u65af\u73c0\u9644\u4ef6"
    PUTFIELD com/myjava/A.msg : Ljava/lang/String;
   L2
    LINENUMBER 11 L2
    ALOAD 0
    LDC "\u5c18\u5c01\u5df2\u4e45\u7684\u6068\u610f"
    PUTFIELD com/myjava/A.msg : Ljava/lang/String;
    RETURN
   L3
    LOCALVARIABLE this Lcom/myjava/A; L0 L3 0
    MAXSTACK = 2
    MAXLOCALS = 1

我写这种帖子其实对我帮助不是很大,主要就是复习的时候用。
我希望可以帮助那些新手,如果能帮到你真的太好了。


嗯?你以为就这样就完了吗???
哪有这么简单。
让我们来看一下最后的一种情况。
前面两种情况,我只是想告诉大家,不管你在哪里赋值,赋值的语句都会被还原到构造方法里面,然后它们的在构造方法里的赋值顺序,和你写的java代码里的顺序是对应的。

这一次,我要研究的是, 1.直接给成员变量赋值2.通过构造块给对象赋值3.通过构造方法赋值这三种赋值的顺序。

class A{
     



    {
     //构造块赋值

        msg="打扫房间哦i啊但是金佛IP圣诞节发票收据阿萨PDF觉得撒泼覅静安寺粕发酵埃斯珀附件";

    }
    private String msg="尘封已久的恨意";//直接给成员变量赋值

    public A(){
     
//通过构造方法赋值,为了看字节码的时候效果更加直观,所以直接我把要赋值的内容直接写死在构造方法里了。
        this.msg="oiasdjfoisajisdaofjosdapjfosipajfpsoaijfjpsoiafjdsopafjspaoifjsdopafjdsapoifjsdapoifjsdpoaijfopdspaofifjsdapofjdsopajfposaijfdposajfposajf";
    }

   public String getMsg(){
     

       return this.msg;
   }


}

以上就是这三种赋值的状态,
OK,我先说结论不管你怎么折腾着三种赋值语句的顺序,在构造方法里赋值的语句,顺序永远是垫底的。
就算你把构造方法写在java代码最前面,运行后一看字节码,构造方法赋值的语句一样排在最后。
直接给对象赋值和构造块赋值,他们俩都在构造方法赋值语句的前面,且它俩的顺序会在java代码里的顺序对应

证据:(字节码文件)

public <init>()V
   L0
    LINENUMBER 13 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
   L1
    LINENUMBER 8 L1
    ALOAD 0
    LDC "\u6253\u626b\u623f\u95f4\u54e6i\u554a\u4f46\u662f\u91d1\u4f5bIP\u5723\u8bde\u8282\u53d1\u7968\u6536\u636e\u963f\u8428PDF\u89c9\u5f97\u6492\u6cfc\u8985\u9759\u5b89\u5bfa\u7c95\u53d1\u9175\u57c3\u65af\u73c0\u9644\u4ef6"
    PUTFIELD com/myjava/A.msg : Ljava/lang/String;
   L2
    LINENUMBER 11 L2
    ALOAD 0
    LDC "\u5c18\u5c01\u5df2\u4e45\u7684\u6068\u610f"
    PUTFIELD com/myjava/A.msg : Ljava/lang/String;
   L3
    LINENUMBER 15 L3
    ALOAD 0
    LDC "oiasdjfoisajisdaofjosdapjfosipajfpsoaijfjpsoiafjdsopafjspaoifjsdopafjdsapoifjsdapoifjsdpoaijfopdspaofifjsdapofjdsopajfposaijfdposajfposajf"
    PUTFIELD com/myjava/A.msg : Ljava/lang/String;
   L4
    LINENUMBER 16 L4
    RETURN
   L5
    LOCALVARIABLE this Lcom/myjava/A; L0 L5 0
    MAXSTACK = 2
    MAXLOCALS = 1

可以看到,在构造方法里赋值的语句,排在构造方法的最后,而那俩赋值都在它前面。

所以直接赋值和构造块赋值就是一种假象,真赋值还是得靠构造方法。


好了,本文结束。

我是尘封已久得恨意,原创码字不易,希望支持一下老铁。

我一直相信费曼学习法。大家一起共勉吧。
有什么不懂得,希望大家多交流吧。

你可能感兴趣的:(java,干货,jvm,编程语言)