1. 程式人生 > >【Java面試題】對於構造方法的疑問?——與類的初始化

【Java面試題】對於構造方法的疑問?——與類的初始化

一,疑問

從學習java至今,我一直對構造方法存在很多疑問,在此將我的疑問throw,你們可以catch到嗎?

面試官 :你說下構造方法吧!

我 :((⊙o⊙)… ,構造方法有什麼聊的,物件的new不是一直在用嗎?) 構造方法是一種特殊的方法,它是一個與類同名且沒有返回值型別的方法。物件的建立就是通過構造方法來完成,其功能主要是完成物件的初始化。當類例項化一個物件時會自動呼叫構造方法。構造方法和其他方法一樣也可以過載。

面試官 :你說構造方法功能是完成物件的初始化,類預設的構造方法怎麼完成物件的初始化,它裡面有沒有程式碼哦!!!

我:(是啊,預設的構造方法沒有程式碼,有也是super,怎麼初始化的)這個... 屬性不是都有預設值得嗎? int型別是0,引用型別是null....

面試官 :解釋下 private int i = 100; 這個i的值也是 0嗎? 如果不是 0,是100,什麼時候給賦的值? 或者是構造方法賦的值嗎? 如果不是構造方法賦的值,程式碼裡能看到那條程式碼給賦的值嗎?

我 :程式碼裡的int i = 100;不是給賦了100嗎,就是這條程式碼給賦的值。

面試官:額,方法的呼叫,執行估計你也應該清楚,沒有特殊邏輯基本都是順序執行,Student stu =new Student(); 呼叫了Student的無參構造方法,這個構造方法基本沒什麼程式碼,你也清楚,請問 private int i = 100; 這條程式碼什麼時候執行,構造方法顯然沒有呼叫這個程式碼!對吧!

我 :(撓頭,程式碼沒有執行這條複製語句啊?)可能是Java的設計者在構造方法中隱式執行了屬性的賦值語句....(我tm機智了,哈哈哈)

面試官 :正確與否先不說,你的說法可以解釋通,還有個問題,我要在構造方法裡面列印這個 i ,會不會存在賦值與列印併發的現象,或者我列印在前,賦值在後引起了錯誤?

我 : 我想規則應該是賦值永遠在程式碼最前面,不會出現這個問題...(鬆了口氣,應該可以了吧!)

面試官:根據你的邏輯,能否解釋下 public static String stuClass = "碼農大學-頸椎病康復班";

我 : 解釋什麼???(一頭霧水)

面試官: 我的意思是,這stuClass是個靜態屬性,我可以直接通過類名呼叫,我並沒有new Studnet(),沒有呼叫構造方法,這個stuClass是怎麼賦值的?你的構造方法隱式賦值理論貌似解釋不通啊?

我: 這個...... (我的心在滴血.....)

我的部分疑問,通過面試中的博弈呈現出來(面試過程為自己思考中的博弈,並非真實發生的),您能否解釋這些問題....

  • new Student() 的過程發生了什麼?
  • 構造方法幹了什麼?
  • 屬性在什麼時候初始化(賦值)?
  • 靜態屬性在什麼時候初始化(賦值)?
  • .............

二,分析

接下來我們通過程式碼分析。

2.1 靜態變數的賦值與靜態程式碼塊的執行

父類相關程式碼

//父類
public class Parent {
	
	/**父類的靜態屬性*/
	public static String preson;
	public static String presonn = "人類";
	
	/**父類的屬性*/
	protected String name;
	protected String namee = "碼農中的吳秀波";
	
	protected int age;
	protected int agee = 18;
	
	/**
	 * 父類的初始化程式碼塊
	 */
	{
		System.out.println("Parent init ...");
		System.out.println("Parent init age:" + age);
		System.out.println("Parent init name:"+ name);
		System.out.println("Parent init namee:"+ namee);
		namee = "碼農中的吳彥祖";
	}
	
	/**
	 * 父類中的靜態初始化程式碼塊
	 */
	static{
		System.out.println("Parent cinit ...");
		System.out.println("Parent cinit preson:"+preson);
		System.out.println("Parent cinit presonn:" + presonn );
		presonn = "人";
	}
	/**
	 * 父類的無參構造方法
	 */
	public Parent() {
		// TODO Auto-generated constructor stub
		System.out.println("Parent constructor ...");
		System.out.println("Parent constructor namee:"+ namee);
	}

}

子類的相關程式碼

//子類
public class Student extends Parent{

	/**子類的靜態屬性*/
	public static String stuclass = "碼農大學-頸椎病康復班";
	
	/**子類的屬性*/
	private int stuNum = 10001;
	
	/**
	 * 子類的初始化程式碼塊
	 */
	{
		System.out.println("Student init ...");
		System.out.println("Student init stuNum :"+ stuNum);
	}
	
	/**
	 * 子類的靜態程式碼塊
	 */
	static{
		System.out.println("Student cinit ...");
		System.out.println("Student cinit stuclass:"+ stuclass);
	}
	/**
	 * 子類無參構造方法
	 */
	public Student() {
		// TODO Auto-generated constructor stub
		System.out.println("Student constructor  ...");
	}
	
	public static void main(String[] args) {
		
	}
	
}

程式碼相對比較簡單,如果只關心程式入口,即子類Student的main方法,執行這個main方法後,您能預計結果是什麼嗎?

//console 輸出
Parent cinit ...
Parent cinit preson:null
Parent cinit presonn:人類
Student cinit ...
Student cinit stuclass:碼農大學-頸椎病康復班

輸出的結果和您預期的一樣嗎?

通過輸出結果我們可知,一個空的main方法的執行,執行順序為:

  • 父類靜態變數的初始化(靜態程式碼塊可以輸出靜態變數的值);
  • 父類靜態程式碼塊的執行(靜態程式碼塊可以重新給靜態變數賦值,暫不演示了);
  • 子類靜態變數的初始化;
  • 子類靜態程式碼塊的執行;

疑問一 :main 方法中並未出現程式碼,main方法的執行為什麼會有如上的輸出???

2.2 變數的賦值、初始化程式碼的執行以及構造方法的執行

public static void main(String[] args) {
		Student stu = new Student();
	}

執行如上程式碼,您能預測出輸出結果嗎?

//console 輸出
Parent cinit ...
Parent cinit preson:null
Parent cinit presonn:人類
Student cinit ...
Student cinit stuclass:碼農大學-頸椎病康復班
--------------------瘋哥線---------------------------
Parent init ...
Parent init age:0
Parent init name:null
Parent init namee:碼農中的吳秀波
Parent constructor ...
Parent constructor namee:碼農中的吳彥祖
Student init ...
Student init stuNum :10001
Student constructor  ...

和您預期的一樣嗎?

通過輸出結果可知,mian 方法以及 Student stu = new Student();程式碼,執行了

  • 靜態相關輸出,同空的mian 方法
  • 父類變數的初始化
  • 父類的初始化程式碼塊
  • 父類的構造方法
  • 子類變數的初始化
  • 子類的初始化程式碼塊
  • 子類的構造方法

疑問二: Student stu = new Student(); 此語句按常理應該只執行父類和子類的構造方法,為什麼會有如此的輸出(執行流程)?

三,解釋-結論-注意

3.1 疑問一的解釋

Java程式語言 -> 編譯器 -> .class -> JVM執行.class ;

Java編譯器會把靜態變數的初始化和靜態程式碼塊順序在位元組碼中生成為<clinit>方法,此方法稱之為類的構造器;

虛擬機器執行位元組碼有如下步驟(想要深入瞭解可以學習JVM、位元組碼相關知識):載入->連線(驗證、準備、解析)->初始化->使用->解除安裝

初始化(執行<clinit>方法):

  • 遇到new、getstatic、putstatic、invokestatic執行初始化操作
  • 使用java.lang.reflect包的方法對類進行呼叫時,如果類沒有進行過初始化,則需要先觸發其初始化
  • 當初始化一個類時,如果發現父類還沒有進行過初始化過,則需要先觸發其父類的初始化
  • 當JVM啟動時,使用者需要指定一個要執行的類(包含main()方法的那個類),虛擬機器會先初始化這個類

如上的初始化(加粗)步驟,完美解釋了 疑問一:main 方法中並未出現程式碼,main執行為什麼如上的輸出???

虛擬機器啟動,我們指定了student類作為啟動類(main方法),虛擬機器載入...初始化這個類,即執行位元組碼中的<clinit>方法,發現父類也沒有初始化,觸發其父類的初始化;

問題:您能舉出不被初始化的例子嗎???

通過 javap -verbose Student.class 命令檢視類的位元組碼

位元組碼檔案-類的構造方法

3.2 疑問二的解釋

位元組碼檔案-例項的初始化方法

通過main()的位元組碼可以看出,Student stu = new Student();轉換成位元組碼指令顯然不是一條(JVM是以一條條指令為單位執行的),指令invokespecial:呼叫例項初始化,父類初始化和私有方法(呼叫了<init>方法)。

<init>:會將變數初始化,初始化語句塊,構造器方法等操作順序封裝到該方法中(父類先於子類執行);

這樣就可以解釋疑問二了,Student stu = new Student();雖然只有一條程式碼,但虛擬機器執行的位元組碼指令可不單單一條指令;

3.3 總結

<clinit>方法是在類載入過程中執行的,而<init>是在物件例項化執行的,所以<clinit>一定比<init>先執行。即執行順序為:

  • 父類的靜態變數初始化
  • 父類的靜態程式碼塊
  • 子類的靜態變數初始化
  • 子類的靜態程式碼塊
  • 父類的變數初始化
  • 父類的初始化程式碼塊
  • 父類的構造方法
  • 子類的變數初始化
  • 子類的初始化程式碼塊
  • 子類的構造方法

相關推薦

Java試題對於構造方法疑問?——初始

一,疑問從學習java至今,我一直對構造方法存在很多疑問,在此將我的疑問throw,你們可以catch到嗎?面試官 :你說下構造方法吧!我 :((⊙o⊙)… ,構造方法有什麼聊的,物件的new不是一直在用嗎?) 構造方法是一種特殊的方法,它是一個與類同名且沒有

Java試題之Object方法詳解

之前看到有人分享的面經,面試官先問Object中有什麼方法,然後再要求解釋每一次方法的作用。 先看看Object中有什麼方法 Object類是Java中所有類的基類。位於java.lang包中,一共有13個方法 方法一 Object() 即Object的構造方法 大

Java試題之類載入:從試題分析Java載入機制

 “載入”(Loading)階段是“類載入”(Class Loading)過程的第一個階段,在此階段,虛擬機器需要完成以下三件事情:        1、 通過一個類的全限定名來獲取定義此類的二進位制位元組流。        2、 將這個位元組流所代表的靜態儲存結構轉化為方法區的執行時資料結

Java試題spring+springMVC+mybatis原理及實現機制(持續更新)

本文將持續更新,主要講解SSM框架的底層原理和實現機制等 1.什麼是IOC? IOC即Inverse of Control,它包括兩個內容:控制與反轉 那到底什麼東西的“控制”被“反轉”了呢?對於軟體而言,即是某一個介面具體實現類的選擇控制權從呼叫類中移除,轉交給第三

java試題Static Nested Class(巢狀) 和 Inner Class(內部類)的不同 、final、static

前言: 本來是想總結一下inner class 的用法,但是卻發現這幾位頗為親近。索性一起拉出來溜溜。 寫作目的: 跟 static , final, inner class 搞好關係,以便將來遇見了,就像用if ,else一樣,一清二楚。 文中的術語定義以java language spec為準。 先想想

Java試題11 什麼是內部類?Static Nested Class 和 Inner Class的不同。

Inner Class(內部類)定義在類中的類。 (一般是JAVA的說法) Nested Class(巢狀類)是靜態(static)內部類。(一般是C++的說法) 靜態內部類:1 建立一個static內部類的物件,不需要一個外部類物件2 不能從一個static內部類的一

Anonymous Inner Class(匿名內部類)是否可以繼承其它?是否可以實現介面?Java試題

回答:匿名內部類在實現時必須藉助一個藉口或者一個抽象類或者一個普通類來構造,從這過層次上講匿名內部類是實現了介面或者繼承了類,但是不能通過extends或implement關鍵詞來繼承類或實現介面。

Java試題之分頁功能的實現

以下內容是根據網上內容以及傳智播客教學整理而來,侵刪。 分頁的實現可分為兩大類:一、資料在Java程式碼中進行分頁,然後取得當前頁資料;二、在資料庫中直接取得當前頁資料。通常面試官都希望聽到後者,因為那才是高效的方法。你如果想讓面試官覺得你的能力高的話你就先否定他的問

抽象(abstract class)和介面(interface)有什麼異同?Java試題

1、抽象類可以包含非抽象的方法,而介面中的方法必須是抽象的。 2、繼承抽象類在Java語言體系中體現一種繼承關係,在合理的繼承關係中,父類和派生類比如按存在is-a關係。而實現介面則體現一種has-a

Java試題如何回答GC相關問題

一個面試官對面試問題的分析 這個帖子的背景是今晚看到je上這張貼:大家都來說說自己最討厭的面試題目吧。,心血來潮寫下的文字,如果能拋磚引玉,能有其他面試官分析一下自己面試時問的問題,那或許是件很有意義的事情。 在公司當技術面試官幾年間,從應屆生到工作十幾年的應聘者都遇到過。先表達一下我自己對面試的觀點:

Java試題一次完整的Http請求過程(非常詳細)

④ 如果在hosts檔案中也沒有找到對應的條目,瀏覽器就會發起一個DNS的系統呼叫,就會向本地配置的首選DNS伺服器(本地DNS伺服器,一般是電信運營商提供的,也可以使用像Google提供的DNS伺服器)發起域名解析請求(遞迴,通過的是UDP協議向DNS的53埠發起請求,這個請求是遞迴的請求,也就是運營商的D

Java試題之三次握手和四次揮手

本文內容大部分轉載自:http://blog.csdn.net/whuslei/article/details/6667471/ 原文獲得了54萬的閱讀量,說明改文章的質量很高 同時,博主在原文的基礎上也補充了一些內容 建立TCP需要三次握手才能建立,而斷開連線則需要

Java試題抽象是否可繼承實體

一道java 常見面試題,網上找到的幾乎每個 java 面試筆試題大全或集錦裡都能找到這道題。 題目如下: 問: 抽象類是否可繼承實體類 (concrete class) 答: 抽象類是可以繼承實體類,但前提是實體類必須有明確的建構函式 答案很明確,可以繼承。其實從Ob

Java試題springMVC的原理?

1.客戶端傳送一個Http請求給Web伺服器,Web伺服器對請求進行解析,如果匹配到DispatcherServlet請求對映路徑,Web容器將請求轉交給DispatcherServlet。 2.Dispatcher接受到請求後,根據請求資訊以及HandlerMappe

Java試題List如何一邊遍歷,一邊刪除?

這是最近面試時被問到的1道面試題,本篇部落格對此問題進行總結分享。 ## 1. 新手常犯的錯誤 可能很多新手(包括當年的我,哈哈)第一時間想到的寫法是下面這樣的: ```java public static void main(String[] args) { List platformList

一道試題一個".java"原始檔中是否可以包括多個(不是內部類)?有什麼限制?

這個面試題的答案在網上一搜一大把 但都是兩句話就結束了,我們來仔細看一下具體是什麼情況! 首先 肯定的一點是一個.java的原始檔中是可以包含多個類的,但是public類只能有一個,並且類名要和檔名相同,如果有兩個public類 就會報出以下的錯誤 這

Java試題Java泛型篇

1. Java中的泛型是什麼 ? 使用泛型的好處是什麼?        泛型是Java SE 1.5的新特性,泛型的本質是引數化型別,也就是說所操作的資料型別被指定為一個引數。好處:        1、型別安全,提供編譯期間的型別檢測        2、前後相容       

Java試題系列Java基礎知識面試題,看這一篇就夠了(持續更新)

文中面試題從茫茫網海中精心篩選,如有錯誤,歡迎指正! 1.前言 ​ 參加過社招的同學都瞭解,進入一家公司面試開發崗位時,填寫完個人資訊後,一般都會讓先做一份筆試題,然後公司會根據筆試題的回答結果,確定要不要繼續此次面試,如果答的不好,有些公司可能會直接說“技術經理或者總監在忙,你先回去等通知吧”,有些公司

Java試題系列Java基礎知識面試題,看這一篇就夠了

路徑 拼接 i++ misc min 中新 dem 總結 內容 文中面試題從茫茫網海中精心篩選,如有錯誤,歡迎指正! 1.前言 參加過社招的同學都了解,進入一家公司面試開發崗位時,填寫完個人信息後,一般都會讓先做一份筆試題,然後公司會根據筆試題的回答結果,確定要不要繼續此

Java試題系列Java基礎知識常見面試題匯總 第二篇

csdn false 2.3 als 報警器 對象創建 第一篇 extend java 文中面試題從茫茫網海中精心篩選,如有錯誤,歡迎指正! 第一篇鏈接:【Java面試題系列】:Java基礎知識常見面試題匯總 第一篇 1.JDK,JRE,JVM三者之間的聯系和區別 你