Java基礎(chǔ)之構(gòu)造器、代碼塊、類加載時機(jī)的用法詳解
1、構(gòu)造器細(xì)節(jié)
一個類可以定義多個不同的構(gòu)造器,即構(gòu)造器重載;
- 比如:我們可以再給Person類定義一個構(gòu)造器,用來創(chuàng)建對象的時候,只指定人名不需要指定年齡。
- 構(gòu)造器名和類名要相同;
- 構(gòu)造器沒有返回值;
- 構(gòu)造器是完成對象的初始化,并不是創(chuàng)建對象;
- 在創(chuàng)建對象時,系統(tǒng)自動的調(diào)用該類的構(gòu)造方法;
- 如果程序員沒有定義構(gòu)造器,系統(tǒng)會自動給類生成一個默認(rèn)無參構(gòu)造器(也叫默認(rèn)構(gòu)造器),比如
Dog (){}
; - 一旦定義了自己的構(gòu)造器,默認(rèn)的構(gòu)造器就覆蓋了,就不能再使用默認(rèn)的無參構(gòu)造器,除非顯式的定義一下,即:
Dog0){}
。
2、代碼塊細(xì)節(jié)
2.1 代碼塊
代碼化塊又稱為初始化塊,屬于類中的成員[即:是類的一部分],類似于方法,將邏輯語句封裝在方法體中,通過包圍起來。
但和方法不同,沒有方法名沒有返回,沒有參數(shù),只有方法體,而且不用通過對象或類顯式調(diào)用,而是加載類時,或創(chuàng)建對象時隱式調(diào)用。
語法:
[修飾符]{ //代碼 }
說明注意:
1)修飾符可選,要寫的話,也只能寫 static
;
2)代碼塊分為兩類,使用static
修飾的叫靜態(tài)代碼塊,沒有static
修飾的,叫普通代碼塊/非靜態(tài)代碼塊;
3)邏輯語句可以為任何邏輯語句(輸入、輸出、方法調(diào)用、循環(huán)、判斷等);
4)代碼塊尾部的;
號可以寫上,也可以省略。
理解:代碼塊相對于另一種形式的構(gòu)造器(對構(gòu)造器的補(bǔ)充機(jī)制),可以做初始化操作。
場景:如果多個構(gòu)造器中有重復(fù)語句,可以抽取到代碼塊中,提高代碼的復(fù)用性。
案例:
public class CodeBlock01 { public static void main(String[] args) { Movie movie = new Movie("你好,李煥英"); System.out.println("==============="); Movie movie2 = new Movie("唐探3", 100, "陳思誠"); } } class Movie { private String name; private double price; private String director; //3個構(gòu)造器-》重載 //解讀 //(1) 下面的三個構(gòu)造器都有相同的語句 //(2) 這樣代碼看起來比較冗余 //(3) 這時我們可以把相同的語句,放入到一個代碼塊中,即可 //(4) 這樣當(dāng)我們不管調(diào)用哪個構(gòu)造器,創(chuàng)建對象,都會先調(diào)用代碼塊的內(nèi)容 //(5) 代碼塊調(diào)用的順序優(yōu)先于構(gòu)造器.. { System.out.println("電影屏幕打開..."); System.out.println("廣告開始..."); System.out.println("電影正是開始..."); }; public Movie(String name) { System.out.println("Movie(String name) 被調(diào)用..."); this.name = name; } public Movie(String name, double price) { this.name = name; this.price = price; } public Movie(String name, double price, String director) { System.out.println("Movie(String name, double price, String director) 被調(diào)用..."); this.name = name; this.price = price; this.director = director; } }
2.2 靜態(tài)代碼塊 & 類加載時機(jī)???
細(xì)節(jié)1
1)?static
代碼塊也叫靜態(tài)代碼塊,作用就是對類進(jìn)行初始化,而且它隨著類的加載而執(zhí)行,并且只會執(zhí)行一次。如果是普通代碼塊,每創(chuàng)建一個對象,就執(zhí)行。
細(xì)節(jié)2
2)?類什么時候被加載
- 創(chuàng)建對象實(shí)例時(new);
- 創(chuàng)建子類對象實(shí)例,父類也會被加載;
- 使用類的靜態(tài)成員時(靜態(tài)屬性,靜態(tài)方法);
案例1:
//1. 創(chuàng)建對象實(shí)例時(new) AA aa = new AA(); class AA { //靜態(tài)代碼塊 static { System.out.println("AA 的靜態(tài)代碼1被執(zhí)行..."); } }
AA 的靜態(tài)代碼1被執(zhí)行...
案例2:
//2. 創(chuàng)建子類對象實(shí)例,父類也會被加載, 而且,父類先被加載,子類后被加載 AA aa2 = new AA(); class BB { //靜態(tài)代碼塊 static { System.out.println("BB 的靜態(tài)代碼1被執(zhí)行...");//1 } } class AA extends BB { //靜態(tài)代碼塊 static { System.out.println("AA 的靜態(tài)代碼1被執(zhí)行...");//2 } }
BB 的靜態(tài)代碼1被執(zhí)行...
AA 的靜態(tài)代碼1被執(zhí)行...
案例3:
//3. 使用類的靜態(tài)成員時(靜態(tài)屬性,靜態(tài)方法) System.out.println(Cat.n1); class Animal { //靜態(tài)代碼塊 static { System.out.println("Animal 的靜態(tài)代碼1被執(zhí)行...");//1 } } class Cat extends Animal { public static int n1 = 999;//靜態(tài)屬性 3 //靜態(tài)代碼塊 static { System.out.println("Cat 的靜態(tài)代碼1被執(zhí)行...");//2 } }
Animal 的靜態(tài)代碼1被執(zhí)行...
Cat 的靜態(tài)代碼1被執(zhí)行...
999
細(xì)節(jié)3
3)普通的代碼塊,在創(chuàng)建對象實(shí)例時,會被隱式的調(diào)用,被創(chuàng)建一次,就會調(diào)用一次。
如果只是使用類的靜態(tài)成員時,普通代碼塊并不會執(zhí)行。
小結(jié):
- 1、static代碼塊是類加載時,執(zhí)行,只會執(zhí)行一次;
- 2、普通代碼塊是在創(chuàng)建對象時調(diào)用的,創(chuàng)建一次,調(diào)用一次。
細(xì)節(jié)4
4)創(chuàng)建一個對象時,在一個類調(diào)用順序時:??
- 調(diào)用靜態(tài)代碼塊和靜態(tài)屬性初始化(注意:靜態(tài)代碼塊和靜態(tài)屬性初始化調(diào)用的優(yōu)先級一樣,如果有多個靜態(tài)代碼塊和多個靜態(tài)變量初始化,則按他們定義的順序調(diào)用);
- 調(diào)用普通代碼塊和普通屬性的初始化(注意:普通代碼塊和普通屬性初始化調(diào)用的優(yōu)先級一樣,如果有多個普通代碼塊和多個普通屬性初始化,則按定義順序調(diào)用);
- 調(diào)用構(gòu)造方法(即構(gòu)造器)。
典型案例:
A a = new A(); class A { { //普通代碼塊 System.out.println("A 普通代碼塊01"); } private int n2 = getN2();//普通屬性的初始化 static { //靜態(tài)代碼塊 System.out.println("A 靜態(tài)代碼塊01"); } //靜態(tài)屬性的初始化 private static int n1 = getN1(); public static int getN1() { System.out.println("getN1被調(diào)用..."); return 100; } public int getN2() { //普通方法/非靜態(tài)方法 System.out.println("getN2被調(diào)用..."); return 200; } //無參構(gòu)造器 public A() { System.out.println("A() 構(gòu)造器被調(diào)用"); } }
A 靜態(tài)代碼塊01
getN1被調(diào)用...
A 普通代碼塊01
getN2被調(diào)用...
A() 構(gòu)造器被調(diào)用
細(xì)節(jié)5
5)構(gòu)造器的最前面其實(shí)隱含了super()
和調(diào)用普通代碼塊,靜態(tài)相關(guān)的代碼塊,屬性初始化,在類加載時,就執(zhí)行完畢,因此是優(yōu)先于構(gòu)造器和普通代碼塊執(zhí)行的。
案例:
new BBB(); class AAA { //父類Object { System.out.println("AAA的普通代碼塊"); } public AAA() { //(1)super() //(2)調(diào)用本類的普通代碼塊 System.out.println("AAA() 構(gòu)造器被調(diào)用...."); } } class BBB extends AAA { { System.out.println("BBB的普通代碼塊..."); } public BBB() { //(1)super() //(2)調(diào)用本類的普通代碼塊 System.out.println("BBB() 構(gòu)造器被調(diào)用...."); } }
AAA的普通代碼塊
AAA() 構(gòu)造器被調(diào)用....
BBB的普通代碼塊...
BBB() 構(gòu)造器被調(diào)用....
細(xì)節(jié)6
6)創(chuàng)建含繼承關(guān)系的一個子類對象時,他們的靜態(tài)代碼塊,靜態(tài)屬性初始化,普通代碼塊,普通屬性初始化,構(gòu)造方法的調(diào)用順序如下:???
- 父類的靜態(tài)代碼塊和靜態(tài)屬性(優(yōu)先級一樣,按定義順序執(zhí)行);
- 子類的靜態(tài)代碼塊和靜態(tài)屬性(優(yōu)先級一樣,按定義順序執(zhí)行);
- 父類的普通代碼塊和普通屬性初始化(優(yōu)先級一樣,按定義順序執(zhí)行);
- 父類的構(gòu)造方法(構(gòu)造器);
- 子類的普通代碼塊和普通屬性初始化(優(yōu)先級一樣,按定義順序執(zhí)行;
- 子類的構(gòu)造方法(構(gòu)造器)。
經(jīng)典案例:
new B02(); class A02 { //父類 private static int n1 = getVal01(); static { System.out.println("A02的一個靜態(tài)代碼塊..");//(2) } { System.out.println("A02的第一個普通代碼塊..");//(5) } public int n3 = getVal02();//普通屬性的初始化 public static int getVal01() { System.out.println("getVal01");//(1) return 10; } public int getVal02() { System.out.println("getVal02");//(6) return 10; } public A02() {//構(gòu)造器 //隱藏 //super() //普通代碼和普通屬性的初始化...... System.out.println("A02的構(gòu)造器");//(7) } } class B02 extends A02 { // private static int n3 = getVal03(); static { System.out.println("B02的一個靜態(tài)代碼塊..");//(4) } public int n5 = getVal04(); { System.out.println("B02的第一個普通代碼塊..");//(9) } public static int getVal03() { System.out.println("getVal03");//(3) return 10; } public int getVal04() { System.out.println("getVal04");//(8) return 10; } //一定要慢慢的去品.. public B02() {//構(gòu)造器 //隱藏了 //super() //普通代碼塊和普通屬性的初始化... System.out.println("B02的構(gòu)造器");//(10) } }
細(xì)節(jié)7
7)靜態(tài)代碼塊只能直接調(diào)用靜態(tài)成員(靜態(tài)屬性和靜態(tài)方法),普通代碼塊可以調(diào)用任意成員。
經(jīng)典案例:
class C02 { private int n1 = 100; private static int n2 = 200; private void m1() {} private static void m2() {} static { //靜態(tài)代碼塊,只能調(diào)用靜態(tài)成員 //System.out.println(n1);錯誤 System.out.println(n2);//ok //m1();//錯誤 m2(); } { //普通代碼塊,可以使用任意成員 System.out.println(n1); System.out.println(n2);//ok m1(); m2(); } }
200
100
200
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
如何在JDK 9中更簡潔使用 try-with-resources 語句
本文詳細(xì)介紹了自 JDK 7 引入的 try-with-resources 語句的原理和用法,以及介紹了 JDK 9 對 try-with-resources 的改進(jìn),使得用戶可以更加方便、簡潔的使用 try-with-resources 語句。,需要的朋友可以參考下2019-06-06Java編程實(shí)現(xiàn)游戲中的簡單碰撞檢測功能示例
這篇文章主要介紹了Java編程中的簡單碰撞檢測功能,涉及java針對坐標(biāo)點(diǎn)的相關(guān)數(shù)學(xué)運(yùn)算操作技巧,需要的朋友可以參考下2017-10-10JVM---jstack分析Java線程CPU占用,線程死鎖的解決
這篇文章主要介紹了JVM---jstack分析Java線程CPU占用,線程死鎖的解決,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09SpringBoot?使用?Sa-Token?完成注解鑒權(quán)功能(權(quán)限校驗(yàn))
Sa-Token?是一個輕量級?java?權(quán)限認(rèn)證框架,主要解決登錄認(rèn)證、權(quán)限認(rèn)證、單點(diǎn)登錄、OAuth2、微服務(wù)網(wǎng)關(guān)鑒權(quán)?等一系列權(quán)限相關(guān)問題,這篇文章主要介紹了SpringBoot使用Sa-Token完成注解鑒權(quán)功能,需要的朋友可以參考下2023-05-05Java自動取款機(jī)ATM案例實(shí)現(xiàn)
本文主要介紹了Java自動取款機(jī)ATM案例實(shí)現(xiàn),整個過程可以分為三部分:登錄賬戶和執(zhí)行取款操作,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08