南陽做網(wǎng)站百度搜索引擎排名規(guī)則
構(gòu)造方法
接上篇,若每次都想下面的setDate方法給對象初始化,未免比較麻煩,那有什么方法可以讓初始化更加簡便呢?
public void setDate(int year, int month, int day){this.year = year;this.month = month;this.day = day;}
答:使用構(gòu)造方法
概念
構(gòu)造方法是一個特殊的成員方法,名字必須與類名相同(沒有返回值,設(shè)置為void也不行),在創(chuàng)建對象時,由編譯器自動調(diào)用,并且在整個對象的生命周期內(nèi)只調(diào)用一次。
方法名 (形參列表){//方法名須與類名相同方法體
}
小拓展:一個對象生成至少有兩步:
- 為對象分配內(nèi)存
- 調(diào)用合適的構(gòu)造方法
構(gòu)造方法的作用就是對對象中的成員進(jìn)行初始化,并不負(fù)責(zé)給對象開辟空間,實例化時可以用構(gòu)造方法對對象進(jìn)行初始化
public Date(int year, int month, int day){this.year = year;this.month = month;this.day = day;}
對日期類可以做以上構(gòu)造方法,這樣在實例化時就可以直接為對象進(jìn)行初始化,初始化代碼如下
Date date = new Date(2004,12,20);
在寫構(gòu)造方法時可以發(fā)生重載:下面代碼中即使兩個構(gòu)造方法的類名一樣,但是參數(shù)不同,不會報錯,發(fā)生了方法的重載,想要調(diào)用哪個就可以調(diào)用哪個。
但是當(dāng)沒有寫任何構(gòu)造方法時,Java會提供一個默認(rèn)不帶參數(shù)的構(gòu)造方法(一旦寫了構(gòu)造方法,Java就不會在提供不帶參數(shù)的構(gòu)造方法),這也是我們不寫構(gòu)造方法對象也能生成的原因。
public Date(){System.out.println("這個是不帶參數(shù)的構(gòu)造方法");}public Date(int year, int month, int day){System.out.println("這個是帶有三個參數(shù)的構(gòu)造方法");this.year = year;this.month = month;this.day = day;}
構(gòu)造方法中可以使用this來調(diào)用其他構(gòu)造方法:
注意事項:
- this( ) 必須是該構(gòu)造方法中的第一條語句
- 格式是
this( 參數(shù) )
- 不能形成環(huán)(像循環(huán)一樣調(diào)來調(diào)去的沒有意義)
以下是在沒有參數(shù)的Date構(gòu)造方法中調(diào)用有參數(shù)的Date構(gòu)造方法代碼
public Date(int year, int month, int day){System.out.println("這個是帶有三個參數(shù)的構(gòu)造方法");this.year = year;this.month = month;this.day = day;}public Date(){this(2024,5,5);System.out.println("這個是不帶參數(shù)的構(gòu)造方法");}
總結(jié):
- 構(gòu)造方法名必須與類名相同
- 構(gòu)造方法沒有返回值類型,設(shè)置為void也不行
- 創(chuàng)建對象時由編譯器自動調(diào)用,并且在對象的生命周期內(nèi)只調(diào)用一次(實例化對象時一定會調(diào)用構(gòu)造方法)
- 構(gòu)造方法可以重載(可以根據(jù)需求寫出不同的構(gòu)造方法)
- 如果用戶沒有顯式定義(自己寫),編譯器會生成一份默認(rèn)的構(gòu)造方法,生成的默認(rèn)構(gòu)造方法一定是無參的(注意:一旦用戶定義,編譯器則不再生成)
- 當(dāng)然,當(dāng)我們自己寫的構(gòu)造方法參數(shù)列表與實際實例化時參數(shù)列表個長度不同,由于編譯器不會再生成不帶參數(shù)的構(gòu)造方法,所以編譯器報錯
- 絕大多數(shù)用public修飾,特殊情況下用private修飾
- 小技巧:idea中自動生成構(gòu)造方法
封裝
面向?qū)ο蟪绦蛉筇匦?#xff1a;封裝、繼承、多態(tài)。(可能的誤區(qū):這三個不是哪個語言的特征,而是面向?qū)ο蟮奶卣?#xff09;
什么是封裝?
封裝:將數(shù)據(jù)和操作數(shù)據(jù)的方法進(jìn)行有機(jī)結(jié)合,隱藏對象的屬性和實現(xiàn)細(xì)節(jié),僅對外公開接口來和對象進(jìn)行 交互
(套殼屏蔽細(xì)節(jié),用東西包裝起來對外隱藏內(nèi)部實際細(xì)節(jié))
總的來說就是對成員變量和成員方法用private進(jìn)行修飾。
達(dá)到的效果:就是該成員變量或成員方法只能在當(dāng)前類內(nèi)部使用,當(dāng)前類外不能使用(可以寫一個方法只能供這個類內(nèi)的方法使用,這樣類外就不知道這個只能供這個類內(nèi)的方法是怎么寫的, 實現(xiàn)了隱藏)
訪問限定符(管當(dāng)前修飾的字段或方法的訪問權(quán)限)
當(dāng)一個字段或方法前沒有任何訪問限定符,則為默認(rèn)權(quán)限 default
包
包的概念
在我們的電腦中,我們?yōu)榱朔诸?#xff0c;會把同一類的東西放到一個文件夾中,但是我們會發(fā)現(xiàn)一個文件夾中不能出現(xiàn)相同名字的文件或文件夾。
類似的,在Java中為了更好地管理類,把類聚集到一個包中,稱為軟件包。包是對類、接口等的封裝機(jī)制的體現(xiàn),是一種對類或者接口等的很好的組織方式,像文件夾一樣,一個包中不能有名字相同的兩個類(但是在一個工程中可以有兩個名字相同的類,只要不在同一個包中)
導(dǎo)入包
Java 中已經(jīng)提供了很多現(xiàn)成的類供我們使用,我們可以使用 import語句導(dǎo)入包比如說導(dǎo)入 java.util 這個包中的 Date 類
import java.util.Date;
如果想導(dǎo)入 java.util 這個包中的所有類可以 import java.util.*
但是同一個包中可能會有名字相同的類,所以建議顯式的指定要導(dǎo)入的類名,否則還是容易出現(xiàn)沖突的情況
import導(dǎo)入的是包下的所有類,用到這個包底下哪個類就回調(diào)用哪個(而不是導(dǎo)入的這個包)
/*java.lang:系統(tǒng)常用基礎(chǔ)類(String,Object),此包從JDK1.1后自動導(dǎo)入
java.lang.reflect:反射編程包
java.net:進(jìn)行網(wǎng)絡(luò)編程開發(fā)包
java.sql:進(jìn)行數(shù)據(jù)庫開發(fā)的支持包
java.util:Java提供的工具程序包(集合類等)非常重要
java.io:I/O編程開發(fā)包*/
可以使用import static導(dǎo)入包中靜態(tài)的方法和字段
import static java.lang.Math.*
用靜態(tài)導(dǎo)入包的好處是可以直接使用靜態(tài)成員而不用通過類名來訪問,使代碼更簡潔
注意事項: import 和 C++ 的 #include 差別很大. C++ 必須 #include 來引入其他文件內(nèi)容, 但是 Java 不需要。import 只是為了寫代碼的時候更方便. import 更類似于 C++ 的 namespace 和 using
static
static修飾成員變量
static修飾的成員變量,稱為靜態(tài)成員變量,也叫類變量,靜態(tài)成員變量最大的特性:不屬于某個具體的對象,是所有對象所共享的
【靜態(tài)成員變量特性】
- 不屬于某個具體的對象,是類的屬性,所有對象共享的,不存儲在某個對象的空間中
- 既可以通過對象訪問,也可以通過類名訪問,但一般更推薦使用類名訪問
- 類變量只有一份且存儲在方法區(qū)當(dāng)中
- 生命周期伴隨類的一生(即:隨類的加載(.class文件通過java文件轉(zhuǎn)化成class對象)而創(chuàng)建,隨類的卸載而銷毀)
- Java當(dāng)中不允許定義局部的靜態(tài)變量(可以通過類名或通過對象的引用訪問,建議用類名訪問)(static修飾的變量是類變量而不是局部變量)
static修飾成員方法
被static修飾的成員方法稱為靜態(tài)成員方法,是類的方法,不是某個對象所特有的。靜態(tài)成員一般是通過靜態(tài)方法來訪問的
【靜態(tài)方法特性】
- 不屬于某個具體的對象,是類方法
- 可以通過對象調(diào)用,也可以通過==類名.靜態(tài)方法名(…)==方式調(diào)用,更推薦使用后者
- 不能在靜態(tài)方法中訪問任何非靜態(tài)成員變量
- == 靜態(tài)方法中不能直接調(diào)用任何非靜態(tài)方法,非靜態(tài)方法中可以調(diào)用靜態(tài)方法==,因為非靜態(tài)方法有this參數(shù),在靜態(tài)方法中調(diào)用時候無法傳遞this引用(靜態(tài)方法中不能使用 static 關(guān)鍵字)
因為:靜態(tài)方法不依賴與對象,可以直接通過類名來訪問
但是:非靜態(tài)方法依賴于對象,要通過對象引用訪問
想要在靜態(tài)方法中調(diào)用非靜態(tài)方法需要先new對象,在通過對象引用訪問- 靜態(tài)方法無法重寫,不能用來實現(xiàn)多態(tài)
注意:靜態(tài)的不依賴于對象,屬于類,不屬于對象
static成員變量初始化
一般通過四種方式:
就地初始化
靜態(tài)代碼塊初始化(下面講)
構(gòu)造方法(少)
get set 方法初始化
代碼塊
概念及分類
使用 {} 定義的一段代碼稱為代碼塊。分下面四種:
- 普通代碼塊:定義在方法中的代碼塊(一般不寫)
- 構(gòu)造代碼塊:也叫實例代碼塊
- 靜態(tài)代碼塊:一般用來初始化靜態(tài)成員變量
static { }
- 同步代碼塊:未來再議
構(gòu)造代碼塊:
//實例代碼塊/構(gòu)造代碼塊{this.name = "z";//實例化對象this.age = 18;this.num = 11;}
靜態(tài)代碼塊:
//靜態(tài)代碼塊static {classname = 1;//靜態(tài)成員變量}
關(guān)于代碼塊:
- 靜態(tài)代碼塊在類加載的時候被執(zhí)行(靜態(tài)成員變量是類的屬性,因此是在JVM加載類時開辟空間并初始化的)
- 如果定義了多個靜態(tài)代碼塊/構(gòu)造代碼塊,則執(zhí)行順序與定義順序有關(guān)
- 靜態(tài)代碼塊不管生成了多少個對象只會執(zhí)行一次->說明這個類只會被執(zhí)行一次
- 實例代碼塊只有在創(chuàng)建對象時才會執(zhí)行
關(guān)于代碼塊順序問題:
由于靜態(tài)代碼塊在加載時就執(zhí)行了,而實例代碼塊在創(chuàng)建對象時才會執(zhí)行,所以靜態(tài)代碼塊的執(zhí)行順序先與實例代碼塊
//實例代碼塊/構(gòu)造代碼塊{this.name = "z";this.age = 18;this.num = 11;System.out.println("構(gòu)造");}//靜態(tài)代碼塊static {classname = 1;System.out.println("靜態(tài)");}//構(gòu)造代碼塊{this.name = "z";this.age = 18;this.num = 11;System.out.println("構(gòu)造");}
上述代碼中,打印順序為下圖,由此可見靜態(tài)代碼塊執(zhí)行順序先與構(gòu)造代碼塊
對象的打印
重新實現(xiàn)toString來打印對象,代碼如下
public class Person {public String name;public String gander;public int age;public Person(String name, String gander, int age){//構(gòu)造方法this.name = name;this.gander = gander;this.age = age;}public String toString(){//重寫toStringreturn "[" + this.name + "," + this.gander + "," + this.age + "]";}public static void main(String[] args) {Person person = new Person("z","女",13);System.out.println(person);//打印時參數(shù)為對象名}
}