Java基礎之構(gòu)造器、代碼塊、類加載時機的用法詳解
1、構(gòu)造器細節(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)會自動給類生成一個默認無參構(gòu)造器(也叫默認構(gòu)造器),比如
Dog (){}; - 一旦定義了自己的構(gòu)造器,默認的構(gòu)造器就覆蓋了,就不能再使用默認的無參構(gòu)造器,除非顯式的定義一下,即:
Dog0){}。
2、代碼塊細節(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)造器的補充機制),可以做初始化操作。
場景:如果多個構(gòu)造器中有重復語句,可以抽取到代碼塊中,提高代碼的復用性。
案例:
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) 這樣當我們不管調(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)代碼塊 & 類加載時機???
細節(jié)1
1)?static代碼塊也叫靜態(tài)代碼塊,作用就是對類進行初始化,而且它隨著類的加載而執(zhí)行,并且只會執(zhí)行一次。如果是普通代碼塊,每創(chuàng)建一個對象,就執(zhí)行。
細節(jié)2
2)?類什么時候被加載
- 創(chuàng)建對象實例時(new);
- 創(chuàng)建子類對象實例,父類也會被加載;
- 使用類的靜態(tài)成員時(靜態(tài)屬性,靜態(tài)方法);
案例1:
//1. 創(chuàng)建對象實例時(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)建子類對象實例,父類也會被加載, 而且,父類先被加載,子類后被加載
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
細節(jié)3
3)普通的代碼塊,在創(chuàng)建對象實例時,會被隱式的調(diào)用,被創(chuàng)建一次,就會調(diào)用一次。
如果只是使用類的靜態(tài)成員時,普通代碼塊并不會執(zhí)行。
小結(jié):
- 1、static代碼塊是類加載時,執(zhí)行,只會執(zhí)行一次;
- 2、普通代碼塊是在創(chuàng)建對象時調(diào)用的,創(chuàng)建一次,調(diào)用一次。
細節(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)用
細節(jié)5
5)構(gòu)造器的最前面其實隱含了super()和調(diào)用普通代碼塊,靜態(tài)相關的代碼塊,屬性初始化,在類加載時,就執(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)用....
細節(jié)6
6)創(chuàng)建含繼承關系的一個子類對象時,他們的靜態(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)
}
}細節(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)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
如何在JDK 9中更簡潔使用 try-with-resources 語句
本文詳細介紹了自 JDK 7 引入的 try-with-resources 語句的原理和用法,以及介紹了 JDK 9 對 try-with-resources 的改進,使得用戶可以更加方便、簡潔的使用 try-with-resources 語句。,需要的朋友可以參考下2019-06-06
JVM---jstack分析Java線程CPU占用,線程死鎖的解決
這篇文章主要介紹了JVM---jstack分析Java線程CPU占用,線程死鎖的解決,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09
SpringBoot?使用?Sa-Token?完成注解鑒權(quán)功能(權(quán)限校驗)
Sa-Token?是一個輕量級?java?權(quán)限認證框架,主要解決登錄認證、權(quán)限認證、單點登錄、OAuth2、微服務網(wǎng)關鑒權(quán)?等一系列權(quán)限相關問題,這篇文章主要介紹了SpringBoot使用Sa-Token完成注解鑒權(quán)功能,需要的朋友可以參考下2023-05-05

