1. 程式人生 > >java 類初始化,例項化順序

java 類初始化,例項化順序

記得在學校初學java時講過,當時也懂了,不過今天看到一個問題時竟然又看不懂,理解不了了....果斷重新梳理了一遍。先上題:

class T  implements Cloneable{
    public static int k = 0;
    public static T t1 = new T("t1");
    public static T t2 = new T("t2");
    public static int i = print("i");
    public static int n = 99;
    public static String s = "s";

    public int j = print("j");
    {
        print("構造快");
    }

    static {
        print("靜態塊");
    }

    public T(String str) {
        System.out.println((++k) + ":" + str + "    i=" + i + "  n=" + n + "   s="+ s);
        ++n; ++ i;
    }

    public static int print(String str){
        System.out.println((++k) +":" + str + "   i=" + i + "   n=" + n + "   s="+ s);
        ++n;
        return ++ i;
    }

    public static void main(String[] args){
        System.out.println("main");
        T t = new T("init");
    }
}
然後上輸出結果:
1:j   i=0   n=0   s=null
2:構造快   i=1   n=1   s=null
3:t1    i=2  n=2   s=null
4:j   i=3   n=3   s=null
5:構造快   i=4   n=4   s=null
6:t2    i=5  n=5   s=null
7:i   i=6   n=6   s=null
8:靜態塊   i=7   n=99   s=s
main
9:j   i=8   n=100   s=s
10:構造快   i=9   n=101   s=s
11:init    i=10  n=102   s=s

先初始化靜態變數跟靜態塊,然後是例項化過程中先初始化成員變數跟構造塊,然後是建構函式呼叫。(靜態塊,靜態屬性或者成員變數都是按照申明順序)


按上述流程,我們分析程式碼:

首先,類裝載,初始化靜態類跟靜態塊

所以執行第二行初始化k,

接下來第三行,初始化T物件,

初始化T物件就到了第9行,此時int 型別 i,n 都未賦值,預設為0,String型別s 則為null,所以打印出 1:j   i=0   n=0   s=null

然後接下來就是10-12行的構造塊,因為上一行i,n 都自增了,所以打印出 2:構造快   i=1   n=1   s=null

成員變數跟構造塊初始化完畢,呼叫建構函式,於是執行18-21,打印出 3:t1    i=2  n=2   s=null 

OK,t1物件初始化完畢了,t2物件同理,不再贅述。

然後就到了第5行,執行變數i的賦值,打印出 7:i   i=6   n=6   s=null

然後執行第6行,變數n賦值為99,注意,n在這之前是6,現在變為99了,接下來的列印能發現區別。

第7行,s賦值為“s”,變數s不再為null了

然後就到靜態塊了,列印結果為 8:靜態塊   i=7   n=99   s=s 看n 跟s的變化;

OK,執行到這完成了一個階段的初始化了,可以理解為是類的裝載,然後就到程式的入口函式main方法中來了 29-32

main函式中先列印了main 然後例項化了個T物件,T物件的例項化同t1 t2的例項化過程,

列印結果自然為main
9:j   i=8   n=100   s=s
10:構造快   i=9   n=101   s=s
11:init    i=10  n=102   s=s

=================================華麗的分割線=====================================

再來個蛋疼的例子學習下:

  1. package test01;     
  2. class Singleton {     
  3. public static Singleton singleton = new Singleton();     
  4. public static int a;     
  5. public static int b = 0;     
  6. private Singleton() {     
  7. super();     
  8.         a++;     
  9.         b++;     
  10.     }     
  11. public static Singleton GetInstence() {     
  12. return singleton;     
  13.     }     
  14. }     
  15. public class MyTest {     
  16. /**   
  17.      * @param args   
  18.      */
  19. public static void main(String[] args) {     
  20.         Singleton mysingleton = Singleton.GetInstence();     
  21.         System.out.println(mysingleton.a);     
  22.         System.out.println(mysingleton.b);     
  23.     }     
  24. }
答案是a=1,b=0。

分析下流程:首先對Singleton的所有的靜態變數分配空間,賦預設的值,所以在這個時候,singleton=null、a=0、b=0。注意b的0是預設值,並不是我們賦的0。

然後對靜態變數賦值。singleton = new Singleton();呼叫構造方法。構造方法裡面a=1、b=1。之後接著順序往下執行,a沒有賦值,保持原狀a=1。b被賦值了,b原先的1被覆蓋,b=0。所以結果就是這麼來的。

================================繼承情況下=========================================

class Test{
    static{
        System.out.println("父類static 塊 1  執行");
    }
    static Sample staticSam1=new Sample("父類 靜態成員staticSam1初始化");
    Sample sam1=new Sample("父類 sam1成員初始化");
    static Sample staticSam2=new Sample("父類 靜態成員staticSam2初始化");
    static{
        System.out.println("父類 static 塊 2  執行");
    }
    Test()
    {
        System.out.println("父類 Test預設建構函式被呼叫");
    }
    Sample sam2=new Sample("父類 sam2成員初始化");

}

class Sample
{
    Sample(String s)
    {
        System.out.println(s);
    }
    Sample()
    {
        System.out.println("Sample預設建構函式被呼叫");
    }
}

class TestSub extends Test
{
    static Sample staticSamSub=new Sample("子類 靜態成員staticSamSub初始化");
    TestSub()
    {
        System.out.println("子類 TestSub 預設建構函式被呼叫");
    }
    Sample sam1=new Sample("子類 sam1成員初始化");
    static Sample staticSamSub1=new Sample("子類 靜態成員staticSamSub1初始化");

    static{System.out.println("子類 static 塊  執行");}
    Sample sam2=new Sample("子類 sam2成員初始化");
}
結果為:
父類static 塊 1  執行
父類 靜態成員staticSam1初始化
父類 靜態成員staticSam2初始化
父類 static 塊 2  執行
子類 靜態成員staticSamSub初始化
子類 靜態成員staticSamSub1初始化
子類 static 塊  執行
父類 sam1成員初始化
父類 sam2成員初始化
父類 Test預設建構函式被呼叫
子類 sam1成員初始化
子類 sam2成員初始化
子類 TestSub 預設建構函式被呼叫

可以看到,繼承情況下先初始化父類靜態,然後子類靜態,然後父類成員變數,父類建構函式,然後是子類成員變數跟建構函式。

相關推薦

java 初始例項順序

記得在學校初學java時講過,當時也懂了,不過今天看到一個問題時竟然又看不懂,理解不了了....果斷重新梳理了一遍。先上題: class T implements Cloneable{ public static int k = 0; public st

Java載入及建立例項(new)順序

Java類載入 1.JVM( Java Virtual Machine,“Java虛擬機器” )的類裝載器ClassLoader(java類),包括系統類、擴充套件類、使用者編寫三種類載入器,負責將java的位元組碼檔案從硬碟讀取到JVM中(記憶體),即首次載入java類時

JAVA初始例項初始時內部的執行順序

       記得剛畢業時,應聘JAVA開發崗位,做招聘單位的筆試時,經常有JAVA類內部的執行順序的考察,就是讓你寫出某個程式的列印結果的順序,現在整理一下。        如果一個類,有構造器,普通塊,靜態塊,那該類初始化時,它的執行順序如何呢?如果它有父類,並且它的父

Java 抽象可以間接實現例項無法直接例項

抽象類無法直接例項化, 它的例項化方式並不是通過普通的new方式來建立物件,而是通過父類的應用來指向子類的例項間接地實現父類的例項化,因為子類在例項化之前,一定會先例項化它的父類。這樣建立了繼承抽象類的子類物件,也就把其父類(抽象類)給例項化了。 注意:介面與抽象類非常類似,但是它不可以被例項化

Java基礎——靜態程式碼塊、構造程式碼塊、建構函式以及Java初始順序

閱讀目錄 建構函式 構造程式碼塊 靜態程式碼塊 Java類初始化順序 靜態程式碼塊:用staitc宣告,jvm載入類時執行,僅執行一次 構造程式碼塊:類中直接用{}定義,每一次建立物件時執行。 執行順序優先順序:靜態塊,main(),構造塊,構造方法。

Java 初始順序

靜態屬性:static 開頭定義的屬性 靜態方法塊: static {} 圈起來的方法塊 普通屬性: 未帶static定義的屬性 普通方法塊: {} 圈起來的方法塊 建構函式: 類名相同的方法 方法: 普通方法 父類靜態變數 > 父類靜態初始塊 &

深入理解Java物件的建立過程:初始例項

摘要:   在Java中,一個物件在可以被使用之前必須要被正確地初始化,這一點是Java規範規定的。在例項化一個物件時,JVM首先會檢查相關型別是否已經載入並初始化,如果沒有,則JVM立即進行載入並呼叫類構造器完成類的初始化。在類初始化過程中或初始化完畢後,根據具體情況才會

Java初始例項

摘要: Java有以下幾種方式建立類物件: 利用new關鍵字 利用反射Class.newInstance 利用Constructor.newIntance(相比Class.newInstance多了有參和私有建構函式) 利用Cloneable/Object.clone() 利

Java初始順序

我們大家都知道,對於靜態變數、靜態初始化塊、變數、初始化塊、構造器,它們的初始化順序以此是(靜態變數、靜態初始化塊)>(變數、初始化塊)>構造器。我們也可以通過下面的測試程式碼來驗證這一點: public class InitialOrderTest { /

java 初始 執行順序

package inheritance; public class InitializeClassObject { public static void main(String[] args) { System.out.println("初始化第一個C類物件");

Java靜態初始例項初始以及構造方法

首先有三個概念需要了解: 一.靜態初始化:是指執行靜態初始化塊裡面的內容。 二.例項初始化:是指執行例項初始化塊裡面的內容。 三.構造方法:一個名稱跟類的名稱一樣的方法,特殊在於不帶返回值。 我們先來看一段程式結果:package com; class Book{

Java提高篇——靜態程式碼塊、構造程式碼塊、建構函式以及Java初始順序

靜態程式碼塊:用staitc宣告,jvm載入類時執行,僅執行一次構造程式碼塊:類中直接用{}定義,每一次建立物件時執行。執行順序優先順序:靜態塊,main(),構造塊,構造方法。 建構函式 public HelloA(){//建構函式 } 關於建構函式,以下幾點

java 的建立如何通過例項物件。

一、 1.建立的類名要大寫。例如Person類,P要大寫。 2.編寫類的屬性,即成員變數。注意屬性對應的資料型別,一般類似身份證號的資料型別都用String。 2.構造方法。當你不寫構造方法時,系

Java基礎學習系列-Java初始例項

Java有以下幾種方式建立類物件: 利用new關鍵字 利用反射Class.newInstance 利用Constructor.newIntance(相比Class.newInstance多了有參和私有建構函式) 利用Cloneable/Object.clon

深入學習Java物件建立的過程:初始例項

  在Java中,一個物件在可以被使用之前必須要被正確地初始化,這一點是Java規範規定的。在例項化一個物件時,JVM首先會檢查相關型別是否已經載入並初始化,如果沒有,則JVM立即進行載入並呼叫類構造器完成類的初始化。在類初始化過程中或初始化完畢後,根據具體情況才會去對類進行例項化。本文試圖對JVM執行類初始

java 初始例項的區別

class A{   public A(){     ……//初始化 }  public static void main(String&nb

JAVA 初始過程

在Java的物件產生的時候虛擬機器jvm會做一系列的行為,而理解這些行為將有助於我們更深入的理解Java 當我們第一次呼叫一個類的某個靜態方法或訪問某個靜態變數時將首先發生類載入,其過程如下 Java虛擬機器JVM會先去方法區中查詢是否已經載入java類名.class如果已

C#之讓你徹底明白物件例項的區別及聯絡

一、前言 在學習類的時候我們肯定離不開物件,它們之間的關係是非常緊密的,要想知道類那麼就一定要知道物件,從物件入手慢慢向類延申,讓你徹底明白類物件和類的聯絡又明白他們的區別。 二、物件和類 物件和類的區別 1,類是一個抽象的概念,它不存在於現實中的時間/空間裡,類只是為所有的物件

Java初始的時機

1.當虛擬機器啟動時,載入使用者指定的main方法所在的類。 2.當在main方法遇到了new關鍵字時,初始化new指令的目標類。 3.當遇到靜態方法呼叫時,初始化靜態方法所在的類。 4.當遇到靜態欄位呼叫時,初始化靜態方法所在的類。 5.子類的初始化時會先觸發父類的初始化。 6

java泛型物件初始--java泛型物件能例項嗎T t=new T()

java中沒法得到泛型引數化型別,因為在編譯期沒法確定泛型引數化型別,也就找不到對應的類位元組碼檔案,自然就不行了  泛型反射的關鍵是獲取ParameterizedType,再呼叫它的getAct