国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Java基礎(chǔ)教程】(七)面向?qū)ο笃?· 第一講:上干貨!面向?qū)ο蟮奶匦?、類與對(duì)象、內(nèi)存結(jié)構(gòu)引用分析、垃圾收集器 GC處理、封裝性詳解、構(gòu)造方法、匿名對(duì)象、簡(jiǎn)單 Java 類~

這篇具有很好參考價(jià)值的文章主要介紹了【Java基礎(chǔ)教程】(七)面向?qū)ο笃?· 第一講:上干貨!面向?qū)ο蟮奶匦?、類與對(duì)象、內(nèi)存結(jié)構(gòu)引用分析、垃圾收集器 GC處理、封裝性詳解、構(gòu)造方法、匿名對(duì)象、簡(jiǎn)單 Java 類~。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

【Java基礎(chǔ)教程】(七)面向?qū)ο笃?· 第一講:上干貨!面向?qū)ο蟮奶匦?、類與對(duì)象、內(nèi)存結(jié)構(gòu)引用分析、垃圾收集器 GC處理、封裝性詳解、構(gòu)造方法、匿名對(duì)象、簡(jiǎn)單 Java 類~,# Java基礎(chǔ)教程,java,開發(fā)語言,java-ee,jvm,后端


?? 篇章介紹

程序是將數(shù)據(jù)和邏輯封裝在一起的代碼段。在Java中,方法是常用的代碼段封裝方式。然而,在Java中,方法必須存在于一個(gè)類中才能使用。因此,我們將進(jìn)入本章的核心內(nèi)容——面向?qū)ο缶幊獭?br>
利用面向?qū)ο笤O(shè)計(jì)的程序可以實(shí)現(xiàn)代碼的重用,并方便開發(fā)者進(jìn)行項(xiàng)目維護(hù)。面向?qū)ο蟮暮诵母拍畎惡蛯?duì)象。因此,本章首先會(huì)講解類和對(duì)象的定義、區(qū)別及使用。隨后,通過實(shí)際分析,我們將介紹封裝性的作用、構(gòu)造方法、this關(guān)鍵字、static關(guān)鍵字、內(nèi)部類等核心概念。

為了加深讀者對(duì)面向?qū)ο蟾拍畹睦斫?,本章還會(huì)探討簡(jiǎn)單Java類的使用、引用實(shí)例分析、數(shù)組操作、String類的特點(diǎn)與常用方法等等。通過本章的學(xué)習(xí),讀者能夠建立起完整的面向?qū)ο缶幊痰幕揪幊棠P?,進(jìn)一步提升編程能力。

本節(jié)學(xué)習(xí)目標(biāo)

  • 理解面向?qū)ο笕笾饕卣鳎?/strong>
  • 掌握類與對(duì)象的區(qū)別及使用;
  • 掌握類中封裝性的基礎(chǔ)實(shí)現(xiàn);
  • 掌握類中構(gòu)造方法以及構(gòu)造方法重載的概念及使用;

1?? 面向?qū)ο蟮娜齻€(gè)特性

面向?qū)ο笫乾F(xiàn)在最為流行的程序設(shè)計(jì)方法,現(xiàn)代的程序開發(fā)幾乎都是以面向?qū)ο鬄榛A(chǔ)。面向?qū)ο蟮木幊趟枷胱钤缡窃?0 世紀(jì) 70 年代的時(shí)候由 IBMSmalltalk 語言推廣的,而后又發(fā)展到了C++ 編程語言,最后由 C++ 衍生出了 Java 編程語言。

在面向?qū)ο笤O(shè)計(jì)廣泛流行之前,軟件行業(yè)中使用最廣泛的開發(fā)模式是面向過程方式。面向過程的操作是以程序的基本功能實(shí)現(xiàn)為主,開發(fā)的過程中只是針對(duì)問題本身的實(shí)現(xiàn),并沒有很好的模塊化的設(shè)計(jì),所以在進(jìn)行代碼維護(hù)的時(shí)候較為麻煩。而面向?qū)ο?,采用的更多的是進(jìn)行子模塊化的設(shè)計(jì),每一個(gè)模塊都需要單獨(dú)存在,并且可以被重復(fù)利用。所以,面向?qū)ο蟮拈_發(fā)更像是一個(gè)具備標(biāo)準(zhǔn)模式的編程開發(fā),每一個(gè)設(shè)計(jì)的子模塊都可以單獨(dú)存在,需要時(shí)只要通過簡(jiǎn)單的組裝即可使用。

下面我將用一個(gè)簡(jiǎn)單的例子 “如何制作一杯咖啡?” 來說明面向過程和面向?qū)ο蟮膮^(qū)別。

面向過程
面向過程的方式就好像在煮咖啡的時(shí)候,你會(huì)一步一步手動(dòng)操作整個(gè)過程。具體步驟可能是這樣的:

  1. 準(zhǔn)備材料:研磨咖啡豆、準(zhǔn)備開水、取出咖啡濾紙等。
  2. 先燒水:將水加熱到適當(dāng)溫度。
  3. 沏泡:將磨好的咖啡豆放入濾紙中,將開水倒入咖啡壺中,慢慢沏泡。
  4. 倒出咖啡:待咖啡沏泡完成后,將咖啡倒入杯子中。
  5. 加糖或牛奶(可選):根據(jù)個(gè)人口味,可以加入糖或牛奶。

在面向過程的方式中,你需要了解每個(gè)步驟的細(xì)節(jié),并按順序手動(dòng)執(zhí)行它們。你是主動(dòng)參與整個(gè)制作過程,并且承擔(dān)了管理、控制和操作的責(zé)任。


面向?qū)ο?/strong>:
相比之下,面向?qū)ο蟮姆绞礁映橄蠛挽`活。在這種情況下,你可以委派給一臺(tái)咖啡機(jī)來完成制作過程。你只需提供相應(yīng)的指令和所需的材料,剩下的工作由咖啡機(jī)來執(zhí)行。

  1. 在咖啡機(jī)的操作面板上,告訴咖啡機(jī)你想要一杯咖啡。
  2. 咖啡機(jī)會(huì)自動(dòng)進(jìn)行研磨、加熱水、沏泡等操作。
  3. 完成后,咖啡機(jī)會(huì)自動(dòng)將咖啡倒入杯子中。

在面向?qū)ο蟮姆绞街?,你不需要了解每個(gè)步驟的具體實(shí)現(xiàn)細(xì)節(jié),而是將任務(wù)委托給咖啡機(jī)這個(gè)具有特定功能的對(duì)象。你只需告訴咖啡機(jī)你的需求,其他具體操作由咖啡機(jī)自行處理,而無需手動(dòng)管理整個(gè)制作過程。

總結(jié):面向過程側(cè)重于手動(dòng)控制和操作每個(gè)步驟,面向?qū)ο髲?qiáng)調(diào)將任務(wù)委派給具有特定功能的對(duì)象。面向?qū)ο蟮姆绞礁映橄蟆㈧`活和模塊化,使得程序更易擴(kuò)展和維護(hù),同時(shí)也隱藏了實(shí)現(xiàn)的復(fù)雜性。

對(duì)于面向?qū)ο蟮某绦蛟O(shè)計(jì)有封裝性、繼承性、多態(tài)性3個(gè)主要特性。下面為讀者簡(jiǎn)單介紹一下這3 種特性,在后面的文章內(nèi)容中會(huì)對(duì)此3個(gè)方面特性進(jìn)行完整的闡述。

1. 封裝性
封裝是面向?qū)ο蟮姆椒ㄋ鶓?yīng)遵循的一個(gè)重要原則。它有兩個(gè)含義:

  • 一層含義是指把對(duì)象的屬性和行為看成一個(gè)密不可分的整體,將這兩者“封裝”在一個(gè)不可分割的獨(dú)立單位(即類)中;
  • 另一層含義指 “信息隱蔽”,把不需要讓外界知道的信息隱藏起來,有些對(duì)象的屬性及行為允許外界用戶知道或使用,但不允許更改,而另一些屬性或行為,則不允許外界知曉,或只允許使用對(duì)象的功能,而盡可能隱蔽對(duì)象的功能實(shí)現(xiàn)細(xì)節(jié)。

封裝機(jī)制在程序設(shè)計(jì)中的表現(xiàn)是,把描述對(duì)象屬性的變量及實(shí)現(xiàn)對(duì)象功能的方法合在一起,定義為 一個(gè)程序單位,并保證外界不能任意更改其內(nèi)部的屬性值,也不能任意調(diào)動(dòng)其內(nèi)部的功能方法。

封裝機(jī)制的另一個(gè)特點(diǎn)是,為封裝在一個(gè)整體內(nèi)的變量及方法規(guī)定了不同級(jí)別的“可見性”或訪問權(quán)限(通過關(guān)鍵字private實(shí)現(xiàn),后面文章中詳細(xì)講解)。

2. 繼承性
繼承是面向?qū)ο蠓椒ㄖ械闹匾拍?,并且是提高軟件開發(fā)效率的重要手段。

首先擁有反映事物一般特性的類,然后在其基礎(chǔ)上派生出反映特殊事物的類。例如,已有 汽車 類,該類中描述了汽車的普遍屬性和行為,進(jìn)一步再產(chǎn)生 轎車 類,轎車的類繼承于汽車的類,轎車類不但擁有汽車類的全部屬性和行為,還增加轎車特有的屬性和行為。

在 Java 程序設(shè)計(jì)中,已有的類可以是 Java 開發(fā)環(huán)境所提供的一批最基本的程序——類庫。用戶開發(fā)的程序類繼承了這些已有的類,這樣,類所描述過的屬性及行為,即已定義的變量和方法,在繼承產(chǎn)生的類中完全可以使用。被繼承的類稱為父類或超類,而經(jīng)繼承產(chǎn)生的類稱為子類或派生類。根據(jù)繼承機(jī)制,派生類繼承了超類的所有成員,并相應(yīng)地增加了自己的一些新的成員。

面向?qū)ο蟪绦蛟O(shè)計(jì)中的繼承機(jī)制,大大增強(qiáng)了程序代碼的可復(fù)用性,提高了軟件的開發(fā)效率,降低了程序產(chǎn)生錯(cuò)誤的可能性,也為程序的修改擴(kuò)充提供了便利。

若一個(gè)子類只允許繼承一個(gè)父類,稱為單繼承;若允許繼承多個(gè)父類,稱為多繼承。目前許多面向?qū)ο蟪绦蛟O(shè)計(jì)語言不支持多繼承,也即存在單繼承局限。而 Java 語言通過接口(interface)的方式來彌補(bǔ)由于Java 不支持多繼承而帶來的子類不能享用多個(gè)父類的成員的缺憾。

3. 多態(tài)性
多態(tài)是面向?qū)ο蟪绦蛟O(shè)計(jì)的又一個(gè)重要特征。多態(tài)是指允許程序中出現(xiàn)重名現(xiàn)象。 Java 語言中含有 方法重載與對(duì)象多態(tài)兩種形式的多態(tài)。

  • 方法重載:在一個(gè)類中,允許多個(gè)方法使用同一個(gè)名字,但方法的參數(shù)不同,完成的功能也不同;
  • 對(duì)象多態(tài):子類對(duì)象可以與父類對(duì)象進(jìn)行相互轉(zhuǎn)換,而且根據(jù)其使用的子類不同完成的功能也不同。

多態(tài)的特性使程序的抽象程度和簡(jiǎn)捷程度更高,有助于程序設(shè)計(jì)人員對(duì)程序的分組協(xié)同開發(fā)。

2?? 類與對(duì)象

面向?qū)ο笫钦麄€(gè) Java 的核心,而類與對(duì)象又是支撐起整個(gè) Java 面向?qū)ο箝_發(fā)的基本概念單元。下面將通過具體的描述來闡述類與對(duì)象的定義及使用。

2.1 基本概念

面向?qū)ο笾蓄惡蛯?duì)象是最基本、最重要的組成單元,類實(shí)際上是表示一個(gè)客觀世界中某類群體的一些基本特征抽象,屬于抽象的概念集合, 如汽車、輪船、 描述的都是某一類事物的公共特征。而對(duì)象就是表示一個(gè)個(gè) 具體的事物,例如:張三同學(xué)、李四的書、王五的汽車,這些都是可以使用的事物,就可以理解為對(duì)象,所以對(duì)象表示的是一個(gè)個(gè)獨(dú)立的個(gè)體。

例如,在現(xiàn)實(shí)生活中, 就可以表示為一個(gè),因?yàn)槿吮旧韺儆谝环N廣義的概念,并不是一個(gè)具體個(gè)體描述。而某一個(gè)具體的人,如張三同學(xué),就可以稱為對(duì)象,可以通過各種信息完整地描述這個(gè)具體的人,如這個(gè)人的姓名年齡、性別 等信息,這些信息在面向?qū)ο蟮母拍钪芯头Q為屬性,當(dāng)然人是可以吃飯、睡覺 的,那么這些人的行為在類中就稱為方法

也就是說如果要使用一個(gè)類,就一定會(huì)產(chǎn)生對(duì)象,每個(gè)對(duì)象之間是靠各個(gè)屬性的不同來進(jìn)行區(qū)分的,而每個(gè)對(duì)象所具備的操作就是類中規(guī)定好的方法,類與對(duì)象的關(guān)系如下圖所示。

【Java基礎(chǔ)教程】(七)面向?qū)ο笃?· 第一講:上干貨!面向?qū)ο蟮奶匦浴㈩惻c對(duì)象、內(nèi)存結(jié)構(gòu)引用分析、垃圾收集器 GC處理、封裝性詳解、構(gòu)造方法、匿名對(duì)象、簡(jiǎn)單 Java 類~,# Java基礎(chǔ)教程,java,開發(fā)語言,java-ee,jvm,后端
圖1 類和對(duì)象

2.2 定義

從之前的概念中可以了解到,類是由屬性和方法組成的。屬性中定義類一個(gè)個(gè) 具體信息,實(shí)際上一個(gè)屬性就是一個(gè)變量或常量,而方法是一些操作的行為,但是在程序設(shè)計(jì)中,定義類也要按照具體的語法要求完成,如果要定義類則需要使用 class 關(guān)鍵字定義,類的定義語法如下。

[public] class 類名稱{
	數(shù)據(jù)類型 屬性(變量);	//聲明成員變量(屬性)
		
	[public] 返回值的數(shù)據(jù)類型 方法名稱(參數(shù)1,參數(shù)2...){ 	//聲明成員方法(行為)
		程序語句;
		[return 表達(dá)式;]
	}
}

下面是一個(gè)定義類的代碼案例:

//	案例1: 定義類
class Book{		//定義一個(gè)新的類
	String title; 	//書的名字
	double price;	//書的價(jià)格
	
	/**
	*輸出對(duì)象完整信息
	*/
	public void getInfo(){
		//此方法將由對(duì)象調(diào)用
		System.out.println("圖書名稱:"+title+",價(jià)格:"+price);
	}
}

此代碼定義了一個(gè) Book 類,在這個(gè)類中定義了兩個(gè)屬性:圖書名稱 (titleString類型)、價(jià)格 (pricedouble 類型),以及一個(gè)取得圖書完整信息的getlnfo()方法。

類定義完成后,肯定無法直接使用,如果要使用,必須依靠對(duì)象,由于類屬于引用數(shù)據(jù)類型,而對(duì)象的產(chǎn)生格式如下:

//格式 1: 聲明并實(shí)例化對(duì)象
類名稱 對(duì)象名稱 = new 類名稱();
//格式 2: 分步完成.先聲明對(duì)象,再實(shí)例化對(duì)象
類名稱 對(duì)象名稱 = null;
對(duì)象名稱 = new 類名稱();

因?yàn)轭悓儆谝脭?shù)據(jù)類型,而引用數(shù)據(jù)類型與基本數(shù)據(jù)類型最大的不同在于需要內(nèi)存的開辟及使用,所以關(guān)鍵字 new 的主要功能就是開辟內(nèi)存空間,即只要是引用數(shù)據(jù)類型(數(shù)組、類與對(duì)象、字符串String…)想使用,就必須使用關(guān)鍵字 new 來開辟空間。

當(dāng)一個(gè)對(duì)象實(shí)例化后就可以按照如下方式利用對(duì)象來操作類的結(jié)構(gòu)。

  • 對(duì)象.屬性:表示要操作類中的屬性內(nèi)容;
  • 對(duì)象.方法():表示要調(diào)用類中的方法。
//	案例2: 使用類——在主類中使用 Book 類
public class TestDemo{
	public static void main(String args[]){
		Book book=new Book();	//聲明并實(shí)例化對(duì)象
		book.title ="Java開發(fā)";	//操作屬性內(nèi)容
		book.price = 89.9;		//操作屬性內(nèi)容
		book.getInfo();			//調(diào)用類中的getInfo0方法
	}
}

程序執(zhí)行結(jié)果:

圖書名稱:Java 開發(fā),價(jià)格:89.9

此程序在主方法中使用關(guān)鍵字 new 實(shí)例化 Book 類的對(duì)象 book。 當(dāng)類產(chǎn)生實(shí)例化對(duì)象后就可以利用 “對(duì)象.屬性"("book.price = 89.9”)與“對(duì)象.方法()”(book.getInfo()) 進(jìn)行類結(jié)構(gòu)的調(diào)用。

案例代碼實(shí)現(xiàn)了一個(gè)最基礎(chǔ)的類使用操作,但是類本身屬于引用數(shù)據(jù)類型,而對(duì)于引用數(shù)據(jù)類型的 執(zhí)行分析就必須結(jié)合內(nèi)存操作來看。下面給出JVM中兩塊內(nèi)存空間區(qū)域的概念(更詳細(xì)的JVM內(nèi)存結(jié)構(gòu)情況將在后面的文章中介紹)。

  • 堆內(nèi)存 (heap):保存每一個(gè)對(duì)象的屬性內(nèi)容,堆內(nèi)存需要用關(guān)鍵字 new 才可以開辟,如果一個(gè)對(duì)象沒有對(duì)應(yīng)的堆內(nèi)存指向,將無法使用;
  • 棧內(nèi)存(stack):保存的是一塊堆內(nèi)存的地址數(shù)值,可以把它想象成一個(gè)int 型變量(每一個(gè) int 型變量只能存放一個(gè)數(shù)值),所以每一塊棧內(nèi)存只能夠保留一塊堆內(nèi)存地址。

對(duì)于以上給出的堆棧內(nèi)存關(guān)系,可能有部分初學(xué)讀者覺得稍微有點(diǎn)抽象,下面換個(gè)角度來補(bǔ)充說明說明這兩塊內(nèi)存空間的作用。

  • 堆內(nèi)存:保存對(duì)象的真正數(shù)據(jù),都是每一個(gè)對(duì)象的屬性內(nèi)容;
  • 棧內(nèi)存:保存的是一塊堆內(nèi)存的空間地址,為了方便理解,可以簡(jiǎn)單地將棧內(nèi)存中保存的數(shù)據(jù)理解為對(duì)象的名稱(Book book), 就假設(shè)保存的是“book”對(duì)象名稱。

這兩塊內(nèi)存空間區(qū)域的內(nèi)存關(guān)系如下圖所示:

【Java基礎(chǔ)教程】(七)面向?qū)ο笃?· 第一講:上干貨!面向?qū)ο蟮奶匦?、類與對(duì)象、內(nèi)存結(jié)構(gòu)引用分析、垃圾收集器 GC處理、封裝性詳解、構(gòu)造方法、匿名對(duì)象、簡(jiǎn)單 Java 類~,# Java基礎(chǔ)教程,java,開發(fā)語言,java-ee,jvm,后端
圖2 堆棧內(nèi)存關(guān)系

如果要想開辟堆內(nèi)存空間,只能依靠關(guān)鍵字new 來進(jìn)行開辟。即:只要看見了關(guān)鍵字new不管何種情況下,都表示要開辟新的堆內(nèi)存空間。

下面以更加詳細(xì)的內(nèi)存關(guān)系圖來解析上邊代碼案例的程序邏輯:

【Java基礎(chǔ)教程】(七)面向?qū)ο笃?· 第一講:上干貨!面向?qū)ο蟮奶匦?、類與對(duì)象、內(nèi)存結(jié)構(gòu)引用分析、垃圾收集器 GC處理、封裝性詳解、構(gòu)造方法、匿名對(duì)象、簡(jiǎn)單 Java 類~,# Java基礎(chǔ)教程,java,開發(fā)語言,java-ee,jvm,后端
圖3 代碼案例的程序邏輯

  • a. 聲明并實(shí)例化對(duì)象:“Book book = new Book();”, 如圖(a) 所示,每一個(gè)堆內(nèi)存都會(huì)存在一個(gè)地址值,這里假設(shè)地址為 “0X0001”;
  • b. 設(shè)置 title 屬性內(nèi)容:"book.title = "Java開發(fā)"; ", 如圖(b) 所示;
  • c. 設(shè)置 price 屬性內(nèi)容:“book.price = 89.9;”, 如圖? 所示。

從上述代碼案例及圖示可以發(fā)現(xiàn),使用對(duì)象時(shí)一定需要一塊對(duì)應(yīng)的堆內(nèi)存空間,而堆內(nèi)存空間的開辟需要通過關(guān)鍵字 new 來完成。每一個(gè)對(duì)象在剛剛實(shí)例化后,里面所有屬性的內(nèi)容都是其對(duì)應(yīng)數(shù)據(jù)類型的默認(rèn)值,只有設(shè)置了屬性內(nèi)容之后,屬性才可以保存內(nèi)容。

區(qū)別于上述案例,下邊案例程序使用了分步的方式來實(shí)現(xiàn)了對(duì)象的聲明與實(shí)例化操作。

//	案例3: 以分步的方式實(shí)例化對(duì)象
public class TestDemo (
	public static void main(String args[]){
		Book bk = null;
		bk = new Book();
		bk.title = "Java開發(fā)";
		bk.price = 89.9;	//操作屬性內(nèi)容
		bk.getInfo();		//調(diào)用類中的getInfo(方法
	}
}

程序執(zhí)行結(jié)果:

圖書名稱:Java 開發(fā),價(jià)格:89.9

此程序首先聲明了一個(gè) Book 類的對(duì)象"bk", 但是這個(gè)時(shí)候由于沒有為其開辟堆內(nèi)存空間,所以 “bk” 對(duì)象還無法使用,然后使用關(guān)鍵字 new 實(shí)例化 “bk”對(duì)象,最后利用對(duì)象為屬性賦值、調(diào)用相應(yīng)的·getInfo()方法。此程序的內(nèi)存關(guān)系圖詳解如下所示:

【Java基礎(chǔ)教程】(七)面向?qū)ο笃?· 第一講:上干貨!面向?qū)ο蟮奶匦?、類與對(duì)象、內(nèi)存結(jié)構(gòu)引用分析、垃圾收集器 GC處理、封裝性詳解、構(gòu)造方法、匿名對(duì)象、簡(jiǎn)單 Java 類~,# Java基礎(chǔ)教程,java,開發(fā)語言,java-ee,jvm,后端
圖4 案例程序的內(nèi)存關(guān)系

上文提到,在代碼執(zhí)行到Book bk = null;時(shí),此時(shí)還未為其開辟堆內(nèi)存空間,所以 “bk” 對(duì)象還無法使用。那么如果此時(shí)使用了沒有實(shí)例化的bk對(duì)象會(huì)如何呢?此時(shí)就會(huì)出現(xiàn) “NullPointerException” (空指針異常)。

如果現(xiàn)在只是聲明了對(duì)象,卻沒有使用關(guān)鍵字new實(shí)例化對(duì)象,便調(diào)用其方法則會(huì)發(fā)生異常,代碼如下:

//	案例4: 使用未實(shí)例化的對(duì)象
public class TestDemo{
	public static void main(String args[]){
		Book book = null;		//聲明對(duì)象
		bk.title ="Java開發(fā)"; 	//操作屬性內(nèi)容
		bk.price = 89.9;
		bk.getInfo();			//調(diào)用類中的getInfo()方法
	}
}

程序執(zhí)行結(jié)果:

Exception in thread "main"
java.lang.NullPointerException
at TestDemo.main(TestDemo.java:12)

程序執(zhí)行完畢會(huì)出現(xiàn)"NullPointerException"的信息,這屬于Java的異常信息,而且這種異常造成的原因只有一個(gè),即在使用引用數(shù)據(jù)類型時(shí)沒有為其開辟堆內(nèi)存空間。

關(guān)于異常體系的更多信息可以瀏覽我的專欄:《專欄 :JAVA異常體系》

3?? 引用分析

引用傳遞是整個(gè) Java 中的精髓所在,而引用傳遞的核心概念也只有一點(diǎn): 一塊堆內(nèi)存空間(保存對(duì)象的屬性信息)可以同時(shí)被多個(gè)棧內(nèi)存共同指向,則每一個(gè)棧內(nèi)存都可以修改同一塊堆內(nèi)存空間的屬性值

在所有的引用分析里面,最關(guān)鍵的還是關(guān)鍵字 “new”。 要注意每一次使用關(guān)鍵字 new 都一定會(huì)開辟新的堆內(nèi)存空間,所以如果在代碼里面聲明兩個(gè)對(duì)象,并且使用了關(guān)鍵字 new 為兩個(gè)對(duì)象 分別進(jìn)行對(duì)象的實(shí)例化操作,那么一定是各自占有各自的堆內(nèi)存空間,并且不會(huì)互相影響。

//	案例5: 聲明兩個(gè)對(duì)象
public class TestDemo {
	public static void main(String args[]){
		Book bookA = new Book();		//聲明并實(shí)例化第一個(gè)對(duì)象
		Book bookB = new Book();		//聲明并實(shí)例化第二個(gè)對(duì)象
		bookA.title ="Java開發(fā)";		//設(shè)置第一個(gè)對(duì)象的屬性內(nèi)容
		bookA.price  =89.8;				//設(shè)置第一個(gè)對(duì)象的屬性內(nèi)容
		bookB.title ="JSP開發(fā)";			//設(shè)置第二個(gè)對(duì)象的屬性內(nèi)容
		bookB.price  =69.8;				//設(shè)置第二個(gè)對(duì)象的屬性內(nèi)容
		bookA.getinfo();			 //調(diào)用類中的方法輸出信息
		bookB.getInfo();
	}
}

程序執(zhí)行結(jié)果:

圖書名稱:Java 開發(fā),價(jià)格:89.8
圖書名稱:JSP 開發(fā),價(jià)格:69.8

本程序首先實(shí)例化了兩個(gè)對(duì)象: bookA、bookB, 然后分別為各自的對(duì)象設(shè)置屬性的內(nèi)容,由于這兩個(gè)對(duì)象分別使用關(guān)鍵字 new 開辟新的內(nèi)存空間,所以各自對(duì)象操作屬性時(shí)互不影響。此程序的執(zhí)行內(nèi)存關(guān)系圖詳解如下:

【Java基礎(chǔ)教程】(七)面向?qū)ο笃?· 第一講:上干貨!面向?qū)ο蟮奶匦浴㈩惻c對(duì)象、內(nèi)存結(jié)構(gòu)引用分析、垃圾收集器 GC處理、封裝性詳解、構(gòu)造方法、匿名對(duì)象、簡(jiǎn)單 Java 類~,# Java基礎(chǔ)教程,java,開發(fā)語言,java-ee,jvm,后端
圖5 案例程序的內(nèi)存關(guān)系

上邊案例代碼聲明并實(shí)例化了兩個(gè)對(duì)象,由于其各自占著各自的內(nèi)存空間,所以不會(huì)互相影響。下面的代碼進(jìn)行簡(jiǎn)單的修改,以實(shí)現(xiàn)對(duì)象引用的關(guān)系配置。

//	案例6: 對(duì)象引用傳遞
public class TestDemo{
	public static void main(String args[]){
		Book bookA = new Book();
		Book bookB = null;			//聲明第二個(gè)對(duì)象
		bookA.title = "Java開發(fā)"; 	//設(shè)置第一個(gè)對(duì)象的屬性內(nèi)容
		bookA.price = 89.8;
		bookB = bookA;				//引用傳遞
		bookB.price = 69.8;			//利用第二個(gè)對(duì)象設(shè)置屬性內(nèi)容
		bookA.getInfo();			//調(diào)用類中的方法輸出信息
	}
}

程序執(zhí)行結(jié)果:

圖書名稱:Java開發(fā),價(jià)格:69.8

本程序首先實(shí)例化了一個(gè) bookA 對(duì)象,接著又聲明了一個(gè) bookB 對(duì)象 (此時(shí)并沒有使用關(guān)鍵字 new 實(shí)例化), 然后分別設(shè)置了bookA 對(duì)象的 titleprice 兩個(gè)屬性的內(nèi)容,最后執(zhí)行了本程序之中 最為關(guān)鍵的一行語句 “bookB = bookA”, 此時(shí)就表示 bookB 的內(nèi)存指向了 bookA 的內(nèi)存空間,也表示 bookA 對(duì)應(yīng)的堆內(nèi)存空間同時(shí)被 bookB 所指向,即:兩個(gè)不同的棧內(nèi)存指向了同一塊堆內(nèi)存空間(引用傳遞),所以當(dāng) bookB 修改屬性內(nèi)容時(shí) (bookB.price = 69.8), 會(huì)直接影響 bookA 對(duì)象的內(nèi)容。

此程序的內(nèi)存關(guān)系圖解析如下所示:

【Java基礎(chǔ)教程】(七)面向?qū)ο笃?· 第一講:上干貨!面向?qū)ο蟮奶匦?、類與對(duì)象、內(nèi)存結(jié)構(gòu)引用分析、垃圾收集器 GC處理、封裝性詳解、構(gòu)造方法、匿名對(duì)象、簡(jiǎn)單 Java 類~,# Java基礎(chǔ)教程,java,開發(fā)語言,java-ee,jvm,后端
圖6 案例程序的內(nèi)存關(guān)系

嚴(yán)格來說,bookAbookB 內(nèi)保存的是對(duì)象的地址信息。因此,在上邊范例中的引用過程實(shí)際上是將 bookA 的地址賦值給了 bookB。在引用的操作過程中,一塊堆內(nèi)存可以被多個(gè)棧內(nèi)存同時(shí)指向;然而,一塊棧內(nèi)存只能保存一塊堆內(nèi)存空間的地址。

//	案例7: 深入觀察引用傳遞
public class TestDemo{
	public static void main(String args[]){
		Book bookA = new Book();	//聲明并實(shí)例化第一個(gè)對(duì)象
		Book bookB = new Book();	//聲明并實(shí)例化第二個(gè)對(duì)象
		bookA.title ="Java開發(fā)"; 	//設(shè)置第一個(gè)對(duì)象的屬性內(nèi)容
		bookA.price =89.8;
		bookB.title ="JSP開發(fā)"; 	//設(shè)置第二個(gè)對(duì)象的屬性內(nèi)容
		bookB.price =69.8;
		bookB = bookA;				//引用傳遞
		bookB.price =100.1; 		//利用第二個(gè)對(duì)象設(shè)置屬性內(nèi)容
		bookA.getInfo();			//調(diào)用類中的方法輸出信息
	 }
}

程序執(zhí)行結(jié)果:

圖書名稱:Java 開發(fā),價(jià)格:100.1

此程序首先分別實(shí)例化了 bookAbookB 兩個(gè)不同的對(duì)象,由于其保存在不同的內(nèi)存空間, 所以設(shè)置屬性時(shí)不會(huì)互相影響。然后發(fā)生了引用傳遞 (bookB = bookA), 由于 bookB 對(duì)象原本存在有指向的堆內(nèi)存空間,并且一塊棧內(nèi)存只能夠保存一塊堆內(nèi)存空間的地址,所以 bookB 要先斷開已有的堆內(nèi)存空間,再去指向 bookA 對(duì)應(yīng)的堆內(nèi)存空間,這個(gè)時(shí)候由于原本的 bookB 內(nèi)存沒有任何指向, bookB 將成為垃圾空間。最后由于 bookB 對(duì)象修改了 price屬性的內(nèi)容。程序的內(nèi)存關(guān)系圖如下所示。

【Java基礎(chǔ)教程】(七)面向?qū)ο笃?· 第一講:上干貨!面向?qū)ο蟮奶匦浴㈩惻c對(duì)象、內(nèi)存結(jié)構(gòu)引用分析、垃圾收集器 GC處理、封裝性詳解、構(gòu)造方法、匿名對(duì)象、簡(jiǎn)單 Java 類~,# Java基礎(chǔ)教程,java,開發(fā)語言,java-ee,jvm,后端
圖7 案例程序的內(nèi)存關(guān)系

通過內(nèi)存分析可以發(fā)現(xiàn),在引用數(shù)據(jù)類型關(guān)系時(shí),一塊沒有任何棧內(nèi)存指向的堆內(nèi)存空間將成為垃圾,所有的垃圾會(huì)不定期地被垃圾收集器 (Garbage Collector)回收,回收后會(huì)被釋放掉其所占用的空間。

雖然Java 支持自動(dòng)的垃圾收集處理,但是在代碼的開發(fā)過程中應(yīng)該盡量減少垃圾空間的產(chǎn)生。

?? 關(guān)于垃圾收集器 GC處理的介紹


在Java中,GC(垃圾回收器)的核心功能是對(duì)內(nèi)存中的對(duì)象進(jìn)行分配和回收。因此,我們對(duì)GC的理解不能僅局限于垃圾收集,還應(yīng)該知道GC決定了內(nèi)存分配的方式。

通常情況下,當(dāng)開發(fā)者創(chuàng)建一個(gè)對(duì)象后,GC會(huì)監(jiān)視該對(duì)象的地址、大小和狀態(tài)。對(duì)象的引用保存在棧內(nèi)存中,而對(duì)象的實(shí)際內(nèi)容保存在堆內(nèi)存中。當(dāng)GC檢測(cè)到堆中的某個(gè)對(duì)象不再被棧所引用時(shí),它將周期性地回收這些被堆內(nèi)存占用的對(duì)象。有了GC的幫助,開發(fā)者無需擔(dān)心內(nèi)存回收的細(xì)節(jié),同時(shí)GC也能最大程度上幫助開發(fā)者防止內(nèi)存泄漏問題。

在Java中,針對(duì)垃圾的標(biāo)記與收集,提供了多種不同的處理分類和策略。垃圾判斷策略主要采用可達(dá)性分析法,而垃圾收集策略主要包括:標(biāo)記-清除、復(fù)制、標(biāo)記-整理等。每種策略都有自己的優(yōu)缺點(diǎn),適用于不同的場(chǎng)景和需求。通過了解不同的GC處理分類,可以更好地優(yōu)化和調(diào)整Java程序的內(nèi)存管理效率。

垃圾判斷或標(biāo)記算法:

  • 引用計(jì)數(shù)法(Reference Counting)
    一種基本的垃圾判斷或標(biāo)記算法。它基于對(duì)象的引用計(jì)數(shù)來確定一個(gè)對(duì)象是否可以被回收。每個(gè)對(duì)象都有一個(gè)引用計(jì)數(shù)器,當(dāng)有新的引用指向該對(duì)象時(shí),計(jì)數(shù)器加一;當(dāng)引用不再指向該對(duì)象時(shí),計(jì)數(shù)器減一。當(dāng)計(jì)數(shù)器為零時(shí),意味著沒有任何引用指向該對(duì)象,就可以將其回收。優(yōu)點(diǎn)是實(shí)現(xiàn)簡(jiǎn)單、低延遲,缺點(diǎn)首先是無法解決循環(huán)引用問題,其次會(huì)帶來額外的開銷。
  • 可達(dá)性分析法(Reachability Analysis)
    Java虛擬機(jī)(JVM)中常用的垃圾回收算法。它基于"可達(dá)性"的概念來判斷對(duì)象是否可以被回收。在可達(dá)性分析法中,GC從一組稱為"根"的初始對(duì)象開始,通過遍歷對(duì)象圖,標(biāo)記所有與根對(duì)象連接的可達(dá)對(duì)象(即還有引用指向的對(duì)象)。未標(biāo)記的對(duì)象則被認(rèn)為是不可達(dá)的,可以被回收。此法相對(duì)復(fù)雜,需要進(jìn)行全局掃描和遍歷對(duì)象圖,可能會(huì)造成較長的停頓時(shí)間。為了減少停頓時(shí)間,它采用了與應(yīng)用程序并發(fā)執(zhí)行或并行處理的技術(shù)來提高垃圾回收效率。

垃圾回收算法:
  • 標(biāo)記-清除算法(Mark and Sweep)
    該算法分為兩個(gè)階段:標(biāo)記階段和清除階段。在標(biāo)記階段中,GC會(huì)標(biāo)記所有活動(dòng)對(duì)象。在清除階段中,GC會(huì)清除所有未被標(biāo)記的對(duì)象,釋放它們所占用的內(nèi)存空間。這種算法容易產(chǎn)生內(nèi)存碎片,并且清除階段的暫停時(shí)間較長。
  • 復(fù)制算法(Copying)
    該算法將堆內(nèi)存劃分為兩個(gè)區(qū)域:一個(gè)使用的區(qū)域(From-space)和一個(gè)空閑的區(qū)域(To-space)。當(dāng)開始垃圾回收時(shí),GC會(huì)將所有活動(dòng)對(duì)象從使用的區(qū)域復(fù)制到空閑的區(qū)域,并且按順序緊湊排列。這種算法消耗了一部分內(nèi)存空間,但避免了內(nèi)存碎片問題。
  • 標(biāo)記-整理算法(Mark and Compact)
    該算法與標(biāo)記-清除算法類似,但在清除階段后,會(huì)將存活的對(duì)象移動(dòng)到堆的一端,并進(jìn)行緊湊排列,以消除內(nèi)存碎片。這種算法相對(duì)于標(biāo)記-清除算法來說,需要更多的時(shí)間來進(jìn)行整理操作。
  • 分代收集算法(Generational)
    分代收集算法是基于觀察到大部分對(duì)象的生命周期短暫的特性而提出的。它將堆內(nèi)存分為不同的代,按照對(duì)象的年齡進(jìn)行劃分,如新生代和老年代。通過將垃圾收集的重心放在新生代上,可以快速地回收生命周期短的對(duì)象。常見的分代收集算法是 新生代采用復(fù)制算法,老年代采用標(biāo)記-清除或標(biāo)記-整理算法。JVM將整個(gè)堆內(nèi)存區(qū)分為:
    • 1、YoungGen(新生代,使用Minor GC回收):YoungGen區(qū)里面的對(duì)象的生命周期比較短,GC對(duì)這些對(duì)象進(jìn)行回收的時(shí)候采用復(fù)制算法。YoungGen 又分為 eden、survivor1(from space)、survivor2(to sapce)。
      eden是在每個(gè)對(duì)象創(chuàng)建的時(shí)候才會(huì)分配的空間,當(dāng)eden無法分配時(shí),則會(huì)自動(dòng)觸發(fā)一次Minor GC。當(dāng)GC每次執(zhí)行時(shí)都會(huì)將eden空間中存活的對(duì)象和survivor1中的對(duì)象拷貝到 survivor2中,此時(shí)edensurvivor1的空間內(nèi)容將被清空。當(dāng)GC執(zhí)行下次回收時(shí)將edensurvivor2中的對(duì)象拷貝到surivor1中,同時(shí)會(huì)清空edensurvivor2空間。按照此類的順序依次執(zhí)行,經(jīng)過數(shù)次回收將依然存活的對(duì)象復(fù)制到 OldGen(年老代)區(qū)。
    • 2、OldGen(年老代,使用Major GC回收):當(dāng)對(duì)象從YoungGen保存到 OldGen后,會(huì)檢測(cè)OldGen的剩余空間是否大于要晉升對(duì)象的大小,此時(shí)會(huì)有兩種處理形式。
      • 如果小于要保存的對(duì)象,則直接進(jìn)行一次Full GC(對(duì)整個(gè)堆進(jìn)行掃描和回收,但是Major GC除外),這樣就可以讓OldGen騰出更多的空間。然后執(zhí)行Minor GC,把YoungGen空間的對(duì)象復(fù)制到OldGen空間。
      • 如果大于要保存的對(duì)象,則會(huì)根據(jù)條件(HandlePromotionFailure配置:是 否允許擔(dān)保分配內(nèi)存失敗,即整個(gè)OldGen空間不足,而YoungGen空間中EdenSurvivor對(duì)象都存活的極端情況。)進(jìn)行Minor GCFull GC回收。

4?? 封裝性分析

封裝屬于面向?qū)ο蟮牡谝淮筇匦裕潜竟?jié)所講解的封裝只是針對(duì)其中的一點(diǎn)進(jìn)行講解,對(duì)于封裝操作由于涉及的內(nèi)容過多,后面會(huì)有完整的介紹。在講解封裝操作之前,首先先要明白一個(gè)問題,即為什么要有封裝?

//	案例8: 觀察沒有封裝的代碼
class Book{			//定義一個(gè)類
	String title;	//書的名字	
	double price;	//書的價(jià)格
	
	public void getInfo(){	// 此方法將由對(duì)象調(diào)用
		System.out.println("圖書名稱:"+title+",價(jià)格:"+price);
	}
}
	
public class TestDemo {
	public static void main(String args[]){
		Book book = new Book();   //聲明并實(shí)例化對(duì)象
		book.title ="Java開發(fā)";   //設(shè)置屬性內(nèi)容
		book.price =-89.9;
		book.getInfo();			//調(diào)用方法
	}
}

程序執(zhí)行結(jié)果:

圖書名稱:Java 開發(fā),價(jià)格: -89.9

本程序首先聲明并實(shí)例化了一個(gè) book 對(duì)象,然后分別設(shè)置屬性的內(nèi)容。但是這個(gè)時(shí)候可以發(fā)現(xiàn),此時(shí)的代碼沒有任何語法錯(cuò)誤,卻存在業(yè)務(wù)邏輯上的錯(cuò)誤,因?yàn)闆]有任何一本書的價(jià)錢是負(fù)數(shù)。造成這種錯(cuò)誤的關(guān)鍵在于沒有檢查要設(shè)置的內(nèi)容,就直接將內(nèi)容賦予了屬性,這樣肯定是不合理的。

就好比銀行,每一個(gè)儲(chǔ)戶不可能自己直接去操作金庫,必須由銀行業(yè)務(wù)人員依照業(yè)務(wù)標(biāo)準(zhǔn)才可以進(jìn)行金錢的操作,并且每一步操作都需要進(jìn)行檢查,而檢查的第一步是需要對(duì)用戶隱藏操作的一些私密流程,那么在這種情況下,就可以使用 private關(guān)鍵字進(jìn)行封裝,將類中的屬性進(jìn)行私有化的操作。

//	案例 9: 使用 private 封裝屬性
class Book{					//定義一個(gè)新的類
	private String title;
	private double price;
	
	public void getInfo(){
		System.out.println(圖書名稱:"+title+",價(jià)格:"+price);
	}
}

public class TestDemo {
	public static void main(String args[]){
		Book book = new Book();		//聲明并實(shí)例化對(duì)象
		book.title ="Java開發(fā)";		//設(shè)置屬性內(nèi)容
		book.price=-89.9;
		book.getInfo();
	}
}

程序編譯結(jié)果:

TestDemo.java:12:錯(cuò)誤:title 可以在Book 中訪問 private
				book.title ="Java 開發(fā)";              //設(shè)置屬性內(nèi)容
TestDemo.java:13:錯(cuò)誤:price可以在 Book 中訪問private 
				book.price=-89.9;
2個(gè)錯(cuò)誤

本程序在聲明 Book 類的屬性時(shí)使用了 private 關(guān)鍵字,這樣就表示 titleprice 兩個(gè)屬性只能夠在 Book 類中被訪問,而其他類不能直接進(jìn)行訪問,所以在主類中使用 Book 類對(duì)象直接調(diào)用 titleprice 屬性時(shí)就會(huì)在編譯時(shí)出現(xiàn)語法錯(cuò)誤。如果要想讓程序可以正常使用,必須想辦法讓外部的程序可以操作類的屬性。所以在開發(fā)中,針對(duì)屬性有這樣一種定義:所有在類中定義的屬性都要求使用 private
明,如果屬性需要被外部所使用,那么按照要求定義相應(yīng)的 setter、getter 方法。

  • setter方法主要是設(shè)置內(nèi)容: public void setTitle(String t), 有參數(shù);
  • getter方法主要是取得屬性內(nèi)容: public String getTitle(), 無參數(shù)。
//	案例 10: 為 Book 類中的封裝屬性設(shè)置setter 、getter 
class Book {
	private String title;
	private double price;
	
	/**
	* 設(shè)置或修改 title 屬性內(nèi)容
	*@param t 接收要設(shè)置的數(shù)據(jù) 
	*/
	public void setTitle(String t){
		title = t;
	}
	
	/**
	*設(shè)置或修改 price 屬性內(nèi)容
	*@param  p 接收要設(shè)置的數(shù)據(jù)
	*/
	public void setPrice(double p){
		if(p>0.0){	//進(jìn)行數(shù)據(jù)驗(yàn)證
			price=p;
		}
	}

	/**
	*取得title 屬性內(nèi)容
	*@return title屬性數(shù)據(jù) 
	*/
	public String getTitle(){
		return title;
	}
	
	/**
	*取得price屬性內(nèi)容
	*@return price屬性數(shù)據(jù) 
	*/
	public double getPrice()(
		return price;
	}

	/**
	*輸出對(duì)象完整信息
	*/
	public void getInfo(){                                        //此方法將由對(duì)象調(diào)用
		System.out.println("圖書名稱:"+title+",價(jià)格:"+price);
	}
}

public class TestDemo{
	public static void main(String args[]){
		Book book = new Book();		//聲明并實(shí)例化對(duì)象 
		book.setTitle("Java 開發(fā)");	//設(shè)置屬性內(nèi)容
		book.setPrice(-89.9);
		book.getInfo();		//調(diào)用方法
	}
}

程序執(zhí)行結(jié)果:

圖書名稱:Java 開發(fā),價(jià)格:0.0

此程序在定義 Book 類時(shí),為封裝的 titleprice 兩個(gè)屬性分別定義了各自的 setter、getter 操作方法(可以在進(jìn)行屬性賦值時(shí)進(jìn)行數(shù)據(jù)的檢查),這樣在主類訪問屬性時(shí)就可以利用 Book 類對(duì)象調(diào)用相應(yīng)的方法進(jìn)行設(shè)置。由于使用 private 封裝的屬性可以在 Book 類中直接進(jìn)行訪問,所以 Book 類中的 getInfo()方法并沒有進(jìn)行任何修改。

5?? 構(gòu)造方法

在實(shí)例化新對(duì)象時(shí),通常需要使用關(guān)鍵字new。然而,在對(duì)象實(shí)例化之前,有時(shí)還需要進(jìn)行一些初始化準(zhǔn)備操作。這就是構(gòu)造方法的作用所在。

構(gòu)造方法是一種特殊的方法,只在創(chuàng)建新對(duì)象時(shí)被調(diào)用。它的定義規(guī)則包括:方法名與類名相同、沒有返回值聲明,并且可以進(jìn)行重載,即一個(gè)類可以有多個(gè)不同參數(shù)的構(gòu)造方法。構(gòu)造方法的存在使得對(duì)象的實(shí)例化更加靈活,可以根據(jù)不同的需求選擇合適的構(gòu)造方法來進(jìn)行對(duì)象的初始化操作。

在實(shí)際的工作中,構(gòu)造方法的核心作用是,在類對(duì)象實(shí)例化時(shí)設(shè)置屬性的初始化內(nèi)容,可以說構(gòu)造方法是為屬性初始化準(zhǔn)備的。

需要注意的是構(gòu)造方法一直存在,實(shí)際上在對(duì)象實(shí)例化的格式中就存在構(gòu)造方法的使用,下面通過對(duì)象的實(shí)例化格式來分析。

類名稱 對(duì)象名稱 = new 類名稱();

格式中的 類名稱() 實(shí)際上調(diào)用了一個(gè)和類名稱一樣的方法,這就是構(gòu)造方法。

通過以上的簡(jiǎn)短分析可以發(fā)現(xiàn),所有的構(gòu)造方法實(shí)際上一直在被我們調(diào)用。但是我們從來沒有去定義一個(gè)構(gòu)造方法,之所以能夠使用構(gòu)造方法,是因?yàn)?在整個(gè)Java類中,為了保證程序可以正常的執(zhí)行,即使用戶沒有定義任何構(gòu)造方法,也會(huì)在程序編譯之后自動(dòng)地為類增加一個(gè)沒有參數(shù)、沒有方法名稱、類名稱相同、沒有返回值的默認(rèn)構(gòu)造方法 。

//	案例 11: 定義構(gòu)造方法
class Book {
	/**
	* Book類無參構(gòu)造方法
	*/
	public Book(){                                         //構(gòu)造方法
		System.out.printin("Book類無參構(gòu)造方法被執(zhí)行了...");
	}
}

public class TestDemo{
	public static void main(String args[]){
		Book book = null;           	//聲明對(duì)象不調(diào)用構(gòu)造
		book = new Book();           	//實(shí)例化對(duì)象調(diào)用構(gòu)造
	}
}

程序執(zhí)行結(jié)果:

Book類無參構(gòu)造方法被執(zhí)行了...

此程序在 Book 類中定義了一個(gè)構(gòu)造方法,可以發(fā)現(xiàn)構(gòu)造方法的名稱與 Book 類名稱相同,沒有返回值聲明,并且構(gòu)造方法只有在使用關(guān)鍵字 new 實(shí)例化對(duì)象時(shí)才會(huì)被調(diào)用一次。

?? 構(gòu)造方法與普通方法的區(qū)別?

  1. 方法名和類名相同:構(gòu)造方法的名稱必須與所屬類的名稱完全相同,而普通方法可以有不同的名稱;
  2. 無返回值類型聲明:構(gòu)造方法沒有顯式的返回類型聲明,包括void關(guān)鍵字。普通方法必須聲明返回類型,除非是void類型;
  3. 不使用return語句返回值:構(gòu)造方法不需要使用return語句來返回值,它會(huì)自動(dòng)創(chuàng)建并返回一個(gè)新對(duì)象。普通方法可以使用return語句來返回一個(gè)具體的值或者null
  4. 在對(duì)象創(chuàng)建時(shí)被調(diào)用:構(gòu)造方法只在對(duì)象創(chuàng)建(new )時(shí)被調(diào)用一次,用于初始化對(duì)象的狀態(tài)。普通方法可以通過“對(duì)象.方法”被多次調(diào)用,根據(jù)需要執(zhí)行特定的邏輯;

總的來說, 構(gòu)造方法用于對(duì)象的實(shí)例化和初始化,而普通方法用于執(zhí)行其他操作和提供功能。所以要是希望在對(duì)象實(shí)例化時(shí)進(jìn)行屬性的賦值操作,則可以使用構(gòu)造方法完成。
//	案例 12: 利用構(gòu)造方法為屬性賦值
class Book{
	private String title;
	private double price;
	
	/**
	* Book 類構(gòu)造方法,用于設(shè)置 title與 price屬性的內(nèi)容
	*@param t title屬性內(nèi)容
	*@param p price屬性內(nèi)容
	*/
	public Book(String t,double p){	//定義構(gòu)造方法
		setTitle(t);				//調(diào)用本類方法
		setPrice(p);				//調(diào)用本類方法
	}
	
	public void setTitle(String t){	//設(shè)置 title 屬性內(nèi)容
		title = t;
	}
	
	public void setPrice(double p){	//設(shè)置 price屬性內(nèi)容
		price = p;
	}
	
	public String getTitle(){		//取得 title屬性內(nèi)容
		return title;
	}
	
	public double getPrice(){		//取得price屬性內(nèi)容
		return price;
	}
	
	public void getInfo(){
		System.out.println("圖書名稱:"+title+", 價(jià)格:"+price);
	}
}

public class TestDemo{
	public static void main(String  args[]){
		Book book = new Book("Java 開發(fā)",69.8);	//聲明并實(shí)例化對(duì)象
		book.getInfo();                        //調(diào)用方法
	}
}

程序執(zhí)行結(jié)果:

圖書名稱:Java 開發(fā),價(jià)格:69.8

此程序在 Book 類中首先定義了一個(gè)有兩個(gè)參數(shù)的構(gòu)造方法,這兩個(gè)參數(shù)主要是接收 titleprice 屬性的內(nèi)容,然后分別調(diào)用類中的 setter 方法為屬性賦值 (也可以直接調(diào)用屬性,不通過 setter方法賦值)。

程序中由于已經(jīng)明確地定義了一個(gè)有參構(gòu)造方法,就不會(huì)再自動(dòng)生成默認(rèn)的構(gòu)造方法,即一個(gè)類中至少保留有一個(gè)構(gòu)造方法。

另外還需要注意的是,此時(shí)類中的結(jié)構(gòu)包含屬性、構(gòu)造方法、普通方法,而編寫的時(shí)候一定要注意順序:首先編寫屬性(必須封裝,同時(shí)提供setter、getter的普通方法), 然后編寫構(gòu)造方法,最后編寫普通方法。這樣的格式才有助于養(yǎng)成良好的編碼習(xí)慣。

而構(gòu)造方法本身也屬于方法,所以可以針對(duì)構(gòu)造方法進(jìn)行重載。由于構(gòu)造方法定義的特殊性,所以在 構(gòu)造方法重載時(shí),要求只注意參數(shù)的類型及個(gè)數(shù)即可。

//	案例 13: 構(gòu)造方法重載
class Book{
	private String title;
	private double price;
	
	/**
	* Book 類無參構(gòu)造方法
	*/
	public Book(){	//無參的,無返回值的構(gòu)造方法
		System.out.println("無參構(gòu)造");
	}

	/**
	* Book 類構(gòu)造方法,用于設(shè)置title屬性的內(nèi)容
	*@param t title 屬性內(nèi)容
	*/
	public Book(String t){	//有一個(gè)參數(shù)的構(gòu)造
		title =t;  			//直接為屬性賦值
		System.out.println("有一個(gè)參數(shù)的構(gòu)造");
	}
	
	/**
	* Book 類構(gòu)造方法,用于設(shè)置title與 price屬性的內(nèi)容
	*@param t title屬性內(nèi)容
	*@param p price屬性內(nèi)容
	*/
	public Book(String t,double p){	//有兩個(gè)參數(shù)的構(gòu)造
		title=t;					//直接為屬性賦值
		price=p;					//直接為屬性賦值
		System.out.println("有兩個(gè)參數(shù)的構(gòu)造");
	}
	
	// setter、getter 略

	public void getInfo(){
		System.outprintln("圖書名稱:"+title+", 價(jià)格:"+price);
	}
}

public class TestDemo{
	public static void main(String  args[]){
		Book book = new Book("Java 開發(fā)");
		book.getInfo();
	}
}

程序執(zhí)行結(jié)果:

有一個(gè)參數(shù)的構(gòu)造
圖書名稱:Java 開發(fā),價(jià)格:0.0

此程序首先在 Book 類中將構(gòu)造方法重載了3次,然后在主類中將調(diào)用有一個(gè)參數(shù)的構(gòu)造,這樣只會(huì)為 title 屬性賦值,而 price屬性為其對(duì)應(yīng)數(shù)據(jù)類型的默認(rèn)值。

需要注意的是,在定義一個(gè)類時(shí),可以為屬性直接設(shè)置默認(rèn)初始值,但是這個(gè)值只有在構(gòu)造執(zhí)行完才會(huì)設(shè)置,否則不會(huì)設(shè)置。而構(gòu)造方法屬于整個(gè)對(duì)象構(gòu)造過程的最后一步,即是留給用戶處理的步驟。

在對(duì)象實(shí)例化的過程中, 一定會(huì)經(jīng)歷類的加載、內(nèi)存的分配、默認(rèn)值的設(shè)置、構(gòu)造方法。在此程序中,只有在整個(gè)構(gòu)造都完成后,才會(huì)真正將 “Java 開發(fā)” 這個(gè)字符串的內(nèi)容設(shè)置給 title 屬性。構(gòu)造完成之前title 都是其對(duì)應(yīng)數(shù)據(jù)類型的默認(rèn)值。
(關(guān)于對(duì)象實(shí)例化更詳細(xì)的過程,將在后面的特別篇專門介紹)。

6?? 匿名對(duì)象

按照之前的內(nèi)存關(guān)系來講,對(duì)象的名字可以解釋為在棧內(nèi)存中保存,而對(duì)象的具體內(nèi)容(屬性)在堆內(nèi)存中保存,這樣一來,沒有棧內(nèi)存指向堆內(nèi)存空間,就是一個(gè)匿名對(duì)象,如圖所示。

【Java基礎(chǔ)教程】(七)面向?qū)ο笃?· 第一講:上干貨!面向?qū)ο蟮奶匦?、類與對(duì)象、內(nèi)存結(jié)構(gòu)引用分析、垃圾收集器 GC處理、封裝性詳解、構(gòu)造方法、匿名對(duì)象、簡(jiǎn)單 Java 類~,# Java基礎(chǔ)教程,java,開發(fā)語言,java-ee,jvm,后端
圖8 匿名對(duì)象的內(nèi)存關(guān)系

//	案例 14: 定義匿名對(duì)象
class Book{
	private String title;
	private double price;
	
	public Book(String t,double p){
		title =t;
		price =p;
	}
	
	// setter、getter 略
	
	public void getInfo(){
		System.out.printin(圖書名稱:"+title+", 價(jià)格:"+price);
	}
}

public class TestDemo  {
	public static void main(String args[]){
		new Book("Java 開發(fā)",69.8).getInfo();	//匿名對(duì)象
	}
}

程序執(zhí)行結(jié)果:

圖書名稱:Java 開發(fā),價(jià)格:69.8

此程序通過匿名對(duì)象調(diào)用了類中的方法,但由于匿名對(duì)象沒有對(duì)應(yīng)的棧內(nèi)存指向,所以只能使用一 次, 一次之后就將成為垃圾,并且等待被 GC 回收釋放。

匿名對(duì)象在Java中用于臨時(shí)創(chuàng)建一個(gè)對(duì)象,并且通常只在一處使用,不需要對(duì)該對(duì)象進(jìn)行命名或多次引用。以下是一些常見的情況,適合使用匿名對(duì)象:

  1. 調(diào)用一個(gè)方法僅一次:如果一個(gè)方法只需被調(diào)用一次且沒有其他需要持有該對(duì)象的地方,可以使用匿名對(duì)象來簡(jiǎn)化代碼;
  2. 作為參數(shù)傳遞:當(dāng)一個(gè)方法接受對(duì)象作為參數(shù)并且這個(gè)對(duì)象只在調(diào)用該方法時(shí)使用一次,可以使用匿名對(duì)象作為方法的參數(shù);
  3. 對(duì)象初始化:在某些情況下,我們需要立即創(chuàng)建一個(gè)對(duì)象,并對(duì)其進(jìn)行一些操作或賦值一些屬性值,但不需要保留對(duì)該對(duì)象的引用;
  4. 鏈?zhǔn)秸{(diào)用:在鏈?zhǔn)椒椒ㄕ{(diào)用中,可以通過返回匿名對(duì)象來實(shí)現(xiàn)連續(xù)操作。例如,StringBuilder類的 append()方法就返回了一個(gè)StringBuilder 對(duì)象,可以使用匿名對(duì)象進(jìn)行鏈?zhǔn)椒椒ㄕ{(diào)用(后面文章中會(huì)詳細(xì)介紹)。

注意,由于匿名對(duì)象沒有名稱,因此無法在其范圍之外訪問或重復(fù)使用。因此,只有在確實(shí)需要臨時(shí)使用對(duì)象且無其他需要持有該對(duì)象的地方時(shí),才適合使用匿名對(duì)象。否則,最好創(chuàng)建命名對(duì)象進(jìn)行引用和復(fù)用。

7?? 簡(jiǎn)單 Java 類

簡(jiǎn)單 Java 類是一種在實(shí)際開發(fā)中使用最多的類的定義形式,在簡(jiǎn)單 Java 類中包含類、對(duì)象、構(gòu)造方法、 private 封裝等核心概念的使用。對(duì)于簡(jiǎn)單 Java 類有如下基本開發(fā)要求:

  • 類名稱存在意義,例如: Book 、Emp;
  • 類中所有的屬性以 private 封裝,封裝后的屬性必須提供 setter 、getter方法;
  • 類中可以提供任意多個(gè)構(gòu)造方法,但是必須保留一個(gè)無參構(gòu)造方法;
  • 類中不允許出現(xiàn)任何輸出語句,所有信息輸出必須交給被調(diào)用處輸出;
  • 類中需要提供有一個(gè)取得對(duì)象完整信息的方法,如 getInfo(), 而且返回 String 型數(shù)據(jù)。

需要明白簡(jiǎn)單Java類不僅僅是對(duì)之前知識(shí)概念的總結(jié),更是以后項(xiàng)目開發(fā)中的重要基礎(chǔ),而在隨后的章節(jié)中將對(duì)此概念進(jìn)行進(jìn)一步的延伸擴(kuò)展。

同時(shí)對(duì)于簡(jiǎn)單Java類也有許多名稱,例如:

  • 普通Java對(duì)象(Plain Ordinary Java Object, POJO):它遵循簡(jiǎn)單的Java類編寫規(guī)則,沒有繼承任何特殊類或?qū)崿F(xiàn)特定接口。POJO通常用于表示領(lǐng)域模型或簡(jiǎn)單的數(shù)據(jù)傳輸對(duì)象,不依賴于框架或庫;
  • 值對(duì)象(Value Object, VO):用于封裝一組相關(guān)的數(shù)據(jù)屬性,通常用于業(yè)務(wù)層與展示層之間的數(shù)據(jù)傳遞,具有可讀性高、只讀的特點(diǎn)。VO對(duì)象中的屬性一般是不可變的,也可能包含一些計(jì)算得到的衍生屬性;
  • 持久化對(duì)象(Persistent Object ,PO) :用于映射數(shù)據(jù)庫中表的記錄,對(duì)象屬性通常與數(shù)據(jù)庫表的字段一一對(duì)應(yīng),通過ORM框架(如Hibernate)將數(shù)據(jù)持久化到數(shù)據(jù)庫中。PO對(duì)象主要用于持久化操作(增刪改查);
  • 數(shù)據(jù)傳輸對(duì)象(Transfer Object, TO):用于在不同層或遠(yuǎn)程服務(wù)之間傳輸數(shù)據(jù),通常包含了多個(gè)屬性,用于將相關(guān)數(shù)據(jù)打包、傳輸和解包。TO 對(duì)象可以用于減少遠(yuǎn)程調(diào)用的次數(shù),提高系統(tǒng)性能。
//	案例 15: 開發(fā) Emp 程序類
class Emp{				//定義一個(gè)雇員類
	private int empno;		//雇員編號(hào)
	private String ename;	//雇員姓名 
	private String job;		//雇員職位
	private double sal;		//基本工資
	private double comm;	//傭金
	
	public Emp(){}			//明確定義一個(gè)無參構(gòu)造方法
	
	public Emp(int eno, String ena, String j, double s, double c){		//有參構(gòu)造
		empno = eno;    //為屬性賦值
		ename = ena;    
		job = j;		
		sal = s;
		comm = c;
	}
	
	public void setEmpno(int e){		//設(shè)置 empno 屬性內(nèi)容
		empno =e;
	}
	public void setEname(String e){		//設(shè)置 ename 屬性內(nèi)容
		ename =e;
	}
	public void setJob(String j){		//設(shè)置 job屬性內(nèi)容
		job  =j;
	}
	public void setSal(double  s){		//設(shè)置 sal屬性內(nèi)容
		sal =s;
	}	
	public void setComm(double c){		//設(shè)置 comm 屬性內(nèi)容
		comm = c;
	}
	public int getEmpno(){			//取得empno 屬性內(nèi)容
		return empno;
	}
	public String getEname(){		//取得ename 屬性內(nèi)容
		return ename;
	}
	public String getJob(){			//取得job屬性內(nèi)容
		return job;
	}
	public double getSal(){			//取得sal屬性內(nèi)容
		return sal;
	}
	public double getComm(){		//取得comm 屬性內(nèi)容
		return comm;
	}

	/**
	* 取得簡(jiǎn)單Java 類的基本信息,信息在被調(diào)用處輸出
	*@return 包含對(duì)象完整信息的字符串?dāng)?shù)據(jù)
	*/
	public String getInfo()(    	//取得完整信息
		return " 雇員編號(hào):"+empno+"\n"+ "雇員姓名:"+ename+"\n"+ "雇員職位:"+job+"\n"+ "基本工資:"+sal+"\n"+ "傭 金:"+comm;
	}
}

此程序使用簡(jiǎn)單 Java 類的基本原則,明確地定義了 Emp 程序類,對(duì)屬性進(jìn)行明確的封裝,同時(shí)提供兩個(gè)構(gòu)造方法(一個(gè)無參構(gòu)造, 一個(gè)有參構(gòu)造), 而 getInfo()取得對(duì)象信息并將內(nèi)容返回給調(diào)用處。

//	案例 16: 編寫測(cè)試程序
public class TestDemo{
	public static void main(String args[]){
		Emp e= new Emp(7369,"SMITH","CLERK",800.0,1.0); 	//實(shí)例化對(duì)象
		System.out.println(e.getInfo());				//取得對(duì)象信息
	}
}

程序執(zhí)行結(jié)果:

雇員編號(hào):7369
雇員姓名: SMITH
雇員職位:CLERK
基本工資:800.0
傭   金:1.0

此程序首先調(diào)用了 Emp 類的有參構(gòu)造方法進(jìn)行 Emp 類對(duì)象的實(shí)例化,然后直接輸出信息。如果要修改某一位雇員的姓名,則可以調(diào)用 setName() 方法完成,例如:“e.setEname("ALLEN");” 就表示將名字修改為 ALLEN, 所以 setter 方法除了具備設(shè)置屬性內(nèi)容外,還具備修改屬性內(nèi)容的功能。

?? 總結(jié)

本文介紹了Java面向?qū)ο缶幊痰囊恍┲匾拍詈吞匦?。首先,討論了Java面向?qū)ο蟮娜齻€(gè)基本特性:封裝、繼承和多態(tài)。這些特性使得Java能夠更好地組織和管理代碼,增強(qiáng)代碼的可讀性和復(fù)用性。

接著,介紹了類與對(duì)象的基本概念和定義語法格式。類是面向?qū)ο笾械暮诵母拍?,它通過定義屬性和方法來描述對(duì)象的特征和行為。對(duì)象則是類的實(shí)例化,并擁有獨(dú)立的狀態(tài)和行為。

而后進(jìn)一步,從JVM內(nèi)存的堆棧結(jié)構(gòu)來詳細(xì)地進(jìn)行了對(duì)象的引用分析。并且概括介紹了Java中的垃圾收集機(jī)制(GC),包括標(biāo)記-清除算法、復(fù)制算法、標(biāo)記-整理算法和分代收集算法等標(biāo)記算法策略及垃圾回收策略。

此外,文章還詳細(xì)解釋了封裝性在Java中的重要性,以及如何使用構(gòu)造方法進(jìn)行對(duì)象的初始化操作。匿名對(duì)象作為臨時(shí)創(chuàng)建的對(duì)象,適合在對(duì)象使用頻率較低或僅需一次使用的情況下使用。

最后,簡(jiǎn)要提及了簡(jiǎn)單Java類的概念和重要性。簡(jiǎn)單Java類是指只包含必要屬性和主要方法的類,具有良好的可讀性和易于理解。

通過本文,讀者可以了解到Java面向?qū)ο缶幊痰幕靖拍詈吞匦?,并?duì)類與對(duì)象、垃圾收集器和封裝等部分有了全面的了解。這些知識(shí)對(duì)于構(gòu)建可靠、高效的Java應(yīng)用程序至關(guān)重要。


? 溫習(xí)回顧上一篇(點(diǎn)擊跳轉(zhuǎn))《【Java基礎(chǔ)教程】(六)程序概念篇 · 末:全面講解Java方法的定義及應(yīng)用、方法重載及遞歸~》

? 繼續(xù)閱讀下一篇(點(diǎn)擊跳轉(zhuǎn))《【Java基礎(chǔ)教程】(八)面向?qū)ο笃?· 第二講:Java 數(shù)組全面解析——?jiǎng)討B(tài)與靜態(tài)初始化、二維數(shù)組、方法參數(shù)傳遞、排序與轉(zhuǎn)置、對(duì)象數(shù)組、操作API~》


本文部分案例及圖片來源:
《第一行代碼JAVA》文章來源地址http://www.zghlxwxcb.cn/news/detail-543415.html

【Java基礎(chǔ)教程】(七)面向?qū)ο笃?· 第一講:上干貨!面向?qū)ο蟮奶匦?、類與對(duì)象、內(nèi)存結(jié)構(gòu)引用分析、垃圾收集器 GC處理、封裝性詳解、構(gòu)造方法、匿名對(duì)象、簡(jiǎn)單 Java 類~,# Java基礎(chǔ)教程,java,開發(fā)語言,java-ee,jvm,后端

到了這里,關(guān)于【Java基礎(chǔ)教程】(七)面向?qū)ο笃?· 第一講:上干貨!面向?qū)ο蟮奶匦?、類與對(duì)象、內(nèi)存結(jié)構(gòu)引用分析、垃圾收集器 GC處理、封裝性詳解、構(gòu)造方法、匿名對(duì)象、簡(jiǎn)單 Java 類~的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包