自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

對象實(shí)例是何時被創(chuàng)建的?

開發(fā) 后端
對象實(shí)例何時被創(chuàng)建,這個問題也許你用一句話就能回答完了。但是它的潛在陷阱卻常常被人忽視,這個問題也許并不像你想的那么簡單,不信請你耐心看下去。

對象實(shí)例何時被創(chuàng)建,這個問題也許你用一句話就能回答完了。但是它的潛在陷阱卻常常被人忽視,這個問題也許并不像你想的那么簡單,不信請你耐心看下去。

我前幾天問一個同學(xué),是不是在調(diào)用構(gòu)造函數(shù)后,對象才被實(shí)例化?他不假思索的回答說是。

請看下面代碼:

Java代碼

  1. Date date=new Date();     
  2.     
  3. em.out.println(date.getTime()); 

 

新手在剛接觸構(gòu)造函數(shù)這個概念的時候。他們常常得出這樣的結(jié)論:對象實(shí)例是在調(diào)用構(gòu)造函數(shù)后創(chuàng)建的。因?yàn)檎{(diào)用構(gòu)造函數(shù)后,調(diào)用引用(date)的實(shí)例方法便不會報NullPointerException的錯誤了。

二、經(jīng)驗(yàn)者的觀點(diǎn)

然而,稍稍有經(jīng)驗(yàn)的Java程序員便會發(fā)現(xiàn)上面的解釋并不正確。這點(diǎn)從構(gòu)造函數(shù)中我們可以調(diào)用this關(guān)鍵字可以看出。

請看下面代碼:

Java代碼

  1. public class Test     
  2.     
  3. {     
  4.     
  5.   public Test()     
  6.     
  7.   {     
  8.     
  9.       this.DoSomething();     
  10.     
  11.   }     
  12.     
  13.        
  14.     
  15.   private void DoSomething()     
  16.     
  17.   {     
  18.     
  19.       System.out.println("do init");     
  20.     
  21.   }     
  22.     
  23. }    

 

這段代碼中我們在構(gòu)造函數(shù)中已經(jīng)可以操作對象實(shí)例。這也就證明了構(gòu)造函數(shù)其實(shí)只是用于初始化,早在進(jìn)入構(gòu)造函數(shù)之前。對象實(shí)例便已經(jīng)被創(chuàng)建了。

三、父類構(gòu)造函數(shù)

當(dāng)創(chuàng)建一個有父類的子類的時候。對象的實(shí)例又是何時被創(chuàng)建的呢?我們也許接觸過下面經(jīng)典的代碼:

Java代碼

  1. public class BaseClass     
  2. {     
  3.     public BaseClass()     
  4.     {     
  5.        System.out.println("create base");     
  6.     }     
  7. }     
  8. public class SubClass     
  9. {     
  10.     public SubClass()     
  11.     {     
  12.        System.out.println("create sub");     
  13.     }     
  14.     public static void main(String[] args)     
  15.     {     
  16.        new SubClass();     
  17.     }     
  18. }    

 

結(jié)果是先輸出create base,后輸出create sub。這個結(jié)果看起來和現(xiàn)實(shí)世界完全一致,先有老爸,再有兒子。因此我相信有很多程序員跟我一樣會認(rèn)為new SubClass()的過程是:實(shí)例化BaseClass->調(diào)用BaseClass構(gòu)造函數(shù)初始化->實(shí)例化SubClass->調(diào)用SubClass構(gòu)造函數(shù)初始化。然而非常不幸的是,這是個錯誤的觀點(diǎn)。

四、奇怪的代碼

以下代碼是為了駁斥上面提到的錯誤觀點(diǎn)。但是這種代碼其實(shí)在工作中甚少出現(xiàn)。

Java代碼

  1. public class BaseClass     
  2. {     
  3.     public BaseClass()     
  4.     
  5.     {     
  6.     
  7.        System.out.println("create base");     
  8.     
  9.        init();     
  10.     
  11.     }     
  12.     protected void init() {     
  13.     
  14.        System.out.println("do init");     
  15.     }     
  16. }     
  17.     
  18. //     
  19.     
  20. public class SubClass     
  21. {     
  22.     public SubClass()     
  23.     {     
  24.     
  25.        System.out.println("create sub");     
  26.     
  27.     }     
  28.     @Override    
  29.     
  30.     protected void init()     
  31.     
  32.     {     
  33.     
  34.        assert this!=null;     
  35.     
  36.        System.out.println("now the working class is:"+this.getClass().getSimpleName());     
  37.     
  38.        System.out.println("in SubClass");     
  39.     
  40.     }     
  41.  
  42.     public static void main(String[] args)     
  43.     
  44.     {     
  45.     
  46.        new SubClass();     
  47.     
  48.     }     
  49.     
  50. }   

 

這段代碼運(yùn)行的結(jié)果是先調(diào)用父類的構(gòu)造函數(shù),再調(diào)用子類的init()方法,再調(diào)用子類的構(gòu)造函數(shù)。

這是一段奇妙的代碼,子類的構(gòu)造函數(shù)居然不是子類***個被執(zhí)行的方法。我們早已習(xí)慣于通過super方便的調(diào)用父類的方法,但是好像從沒這樣嘗試從父類調(diào)用子類的方法。

再次聲明,這只是個示例。是為了與您一起探討對象實(shí)例化的秘密。通過這個示例,我們再次印證了開頭的觀點(diǎn):早在構(gòu)造函數(shù)被調(diào)用之前,實(shí)例便已被創(chuàng)造。若該對象有父類,則早在父類的構(gòu)造函數(shù)被調(diào)用之前,實(shí)例也已被創(chuàng)造。這讓java顯得有些不面向?qū)ο?,原來老子兒子其?shí)是一塊兒出生的。

五、奇怪但危險的代碼

本篇是對上篇奇怪代碼的延續(xù)。但是這段代碼更加具有疑惑性,理解不當(dāng)將會讓你出現(xiàn)致命失誤。

請看下面代碼:

Java代碼

  1. public class BaseClass {     
  2.  
  3.     public BaseClass()     
  4.     
  5.     {     
  6.     
  7.        System.out.println("create base");     
  8.     
  9.        init();     
  10.     
  11.     }     
  12.  
  13.     protected void init() {     
  14.     
  15.        System.out.println("in base init");     
  16.     
  17.     }     
  18.     
  19. }     
  20.     
  21. public class SubClass extends BaseClass{     
  22.  
  23.     int i=1024;     
  24.     
  25.     String s="13 leaf";     
  26.     
  27.       
  28.     
  29.     public SubClass()     
  30.     
  31.     {     
  32.     
  33.        System.out.println("create sub");     
  34.     
  35.        init();     
  36.     
  37.     }     
  38.  
  39.     @Override    
  40.     
  41.     protected void init() {     
  42.     
  43.        assert this!=null;     
  44.     
  45.        System.out.println("now the working class is:"+this.getClass().getSimpleName());     
  46.     
  47.        System.out.println("in SubClass");     
  48.     
  49.        /////////////great line/////////////////     
  50.     
  51.        System.out.println(i);     
  52.     
  53.        System.out.println(s);     
  54.     
  55.     }     
  56.  
  57.     public static void main(String[] args) {     
  58.     
  59.        new SubClass();     
  60.     
  61.        //oh!my god!!     
  62.     
  63.     }     
  64.     
  65. }   

 

這段代碼相比上一篇,只是在子類中添加了一些成員變量。而我們的目標(biāo)正是集中在討論成員變量初始化的問題上。

這段代碼的執(zhí)行順序是:父類、子類實(shí)例化->調(diào)用父類構(gòu)造函數(shù)->調(diào)用子類init()方法->調(diào)用子類構(gòu)造函數(shù)->調(diào)用子類init()方法。最終的輸出結(jié)果向我們揭示了成員變量初始化的秘密。

當(dāng)父類構(gòu)造函數(shù)調(diào)用子類的init()方法的時候。子類的成員變量統(tǒng)統(tǒng)是空的,這個空是指的低級初始化。(值類型為0,布爾類型為false,引用類型為null)。而當(dāng)子類構(gòu)造函數(shù)調(diào)用init()方法的時候,成員變量才真正被初始化。這是一個危險的訊息,那就是使用父類構(gòu)造函數(shù)調(diào)用子類時存在成員變量未初始化的風(fēng)險。

我們的討論也到此為止了。再次回顧,總結(jié)一下實(shí)例何時被創(chuàng)建這個問題。我得出了以下結(jié)論:

本文到此便結(jié)束了。鑒于本人才疏學(xué)淺,若是專業(yè)術(shù)語有錯誤,或是哪里講的不對,也歡迎各位高手拍磚。

附上第五篇中SubClass的部分字節(jié)碼,方便大家深入理解:

Java代碼

  1. public SubClass();     
  2.     
  3.       aload_0 [this//aload_0是啥?     
  4.     
  5.       invokespecial ques.BaseClass() [26//調(diào)用父類構(gòu)造函數(shù)     
  6.     
  7.       aload_0 [this]     
  8.     
  9.      sipush 1024 //初始化i成員變量     
  10.     
  11.      putfield ques.SubClass.i : int [28]     
  12.     
  13.       aload_0 [this]     
  14.     
  15.      ldc "13 leaf"> [30//初始化s成員變量     
  16.     
  17.      putfield ques.SubClass.s : java.lang.String [32]     
  18.     
  19.      getstatic java.lang.System.out : java.io.PrintStream [34]     
  20.     
  21.      ldc "create sub"> [40]     
  22.     
  23.      invokevirtual java.io.PrintStream.println(java.lang.String) : void [42]     
  24.     
  25.      aload_0 [this]     
  26.     
  27.     invokevirtual ques.SubClass.init() : void [48//調(diào)用init     
  28.     
  29.      return    

【編輯推薦】

  1. Java序列化的機(jī)制和原理
  2. Java Socket通信的序列化和反序列化代碼介紹
  3. Java輸入數(shù)據(jù)流詳解
  4. Java語言深入 文件和流
  5. Java對象序列化
責(zé)任編輯:金賀 來源: ITEYE博客
相關(guān)推薦

2011-04-15 17:07:13

Java

2024-05-29 08:46:19

2010-10-08 10:52:36

JavaScript對

2021-08-10 07:27:42

Python引用計(jì)數(shù)法

2020-02-25 16:00:28

JavaScript數(shù)據(jù)技術(shù)

2024-04-01 08:23:20

代碼Javajavascript

2010-11-19 09:48:48

ORACLE創(chuàng)建實(shí)例

2010-09-10 15:37:44

SQL函數(shù)

2009-08-20 17:22:45

C# FileSyst

2019-09-09 16:19:42

智慧快遞箱末端投遞末端網(wǎng)點(diǎn)

2010-08-26 11:01:05

DHCP服務(wù)器

2010-11-19 09:30:01

Oracle創(chuàng)建實(shí)例

2010-11-19 10:01:08

Oracle創(chuàng)建實(shí)例

2020-10-21 14:54:02

RustGolang開發(fā)

2024-08-28 10:04:17

2015-07-30 09:46:42

開源項(xiàng)目

2020-04-24 16:05:06

Javascript代碼前端

2010-06-17 18:57:11

UML對象關(guān)系

2010-04-20 15:47:25

Oracle實(shí)例

2022-01-24 16:56:47

數(shù)字盧布數(shù)字錢包貨幣
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號