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