摘要:構(gòu)造方法是在對(duì)象實(shí)例初始化過程中具有舉足輕重的地位,并且提供了多種方式來定義構(gòu)造方法。在中創(chuàng)建對(duì)象的開銷是相當(dāng)?shù)偷模⑶宜俣群芸臁?duì)象終結(jié)器前面我們講述的都是構(gòu)造方法和對(duì)象初始化相關(guān)的主題,但還未提及他們的反面對(duì)象銷毀。
原文鏈接:http://www.javacodegeeks.com/2015/09/how-to-create-and-destroy-objects.html
本文是Java進(jìn)階課程的第一部分。
本課程的目標(biāo)是幫你更有效的使用Java。其中討論了一些高級(jí)主題,包括對(duì)象的創(chuàng)建、并發(fā)、序列化、反射以及其他高級(jí)特性。本課程將為你的精通Java的旅程提供指導(dǎo)。
內(nèi)容提綱引言
實(shí)例構(gòu)造
2.1 隱式(產(chǎn)生的)構(gòu)造方法
2.2 無參構(gòu)造方法
2.3 有參構(gòu)造方法
2.4 初始化代碼塊
2.5 保證構(gòu)造默認(rèn)值
2.6 可見性
2.7 垃圾回收
2.8 對(duì)象終結(jié)器
靜態(tài)初始化
構(gòu)造器模式
4.1 單例模式
4.2 工具類/輔助類
4.3 工廠模式
4.4 依賴注入
源碼下載
下章概要
1. 引言在TIOBE 編程語言排名中,Sun 公司于1995年開發(fā)的Java語言是世界上使用最廣泛的編程語言之一。作為一種通用編程語言,因?yàn)閺?qiáng)大的工具包和運(yùn)行時(shí)環(huán)境、簡單的語法、豐富的平臺(tái)支持(一次編寫,到處運(yùn)行)以及的異常活躍的社區(qū)支持,Java語言對(duì)軟件開發(fā)工程師極具吸引力。
在這一系列的文章中,涵蓋了Java相關(guān)的高級(jí)內(nèi)容,因此假設(shè)讀者已具有基本語言知識(shí)。這并不是一個(gè)完整的參考手冊(cè),而是讓你的技能更上一層樓的詳盡指南。
本課程中包含了大量的代碼片段,在有些對(duì)方為了做對(duì)比,會(huì)同時(shí)提供Java 7和Java 8的示例。
2. 實(shí)例構(gòu)造作為一種面向?qū)ο笳Z言,對(duì)象的創(chuàng)建也許就是Java語言中最重要的概念之一。構(gòu)造方法是在對(duì)象實(shí)例初始化過程中具有舉足輕重的地位,并且Java提供了多種方式來定義構(gòu)造方法。
2.1 隱式(產(chǎn)生的)構(gòu)造方法Java允許在定義類時(shí)不聲明任何的構(gòu)造方法,并這并不代表類沒有構(gòu)造方法。我們看下面類的定義:
package com.javacodegeeks.advanced.construction; public class NoConstructor { }
這個(gè)類未定義構(gòu)造方法,但是Java編譯器會(huì)為其隱式生成一個(gè),從而使我們可以使用new關(guān)鍵字來創(chuàng)建新的對(duì)象實(shí)例。
final NoConstructor noConstructorInstance = new NoConstructor();2.2 無參構(gòu)造方法
無參構(gòu)造方法是最簡單的通過顯式聲明來替代Java編譯生成構(gòu)造方法的方式。
package com.javacodegeeks.advanced.construction; public class NoArgConstructor { public NoArgConstructor() { // Constructor body here } }
在使用new關(guān)鍵字創(chuàng)建新的對(duì)象實(shí)例時(shí),上面的構(gòu)造方法就會(huì)被調(diào)用。
2.3 有參構(gòu)造方法有參構(gòu)造方法最有意思并且廣泛使用,通過指定參數(shù)來定制新實(shí)例的創(chuàng)建。下面的例子中定義了一個(gè)有兩個(gè)參數(shù)的構(gòu)造方法。
package com.javacodegeeks.advanced.construction; public class ConstructorWithArguments { public ConstructorWithArguments(final String arg1,final String arg2) { // Constructor body here } }
這種場景中,當(dāng)使用new關(guān)鍵字來創(chuàng)建實(shí)例時(shí),需要同時(shí)提供構(gòu)造方法上定義的兩個(gè)參數(shù)。
final ConstructorWithArguments constructorWithArguments = new ConstructorWithArguments( "arg1", "arg2" );
有趣的是構(gòu)造方法之間可以通過this關(guān)鍵字互相調(diào)用。在實(shí)踐中,推薦通過使用this把多個(gè)構(gòu)造方法鏈起來以減少代碼重復(fù),并從基礎(chǔ)上使對(duì)象具有單一的初始化入口。作為示例,下面的代碼中定義了只有一個(gè)參數(shù)的構(gòu)造方法。
public ConstructorWithArguments(final String arg1) { this(arg1, null); }2.4 初始化代碼塊
除了構(gòu)造方法,Java還提供了通過初始化代碼塊進(jìn)行初始化的邏輯。這種用法雖然少見,但多了解一些也沒害處。
package com.javacodegeeks.advanced.construction; public class InitializationBlock { { // initialization code here } }
另一方面,初始化代碼塊也可被看作是無參的隱式構(gòu)造方法。在一個(gè)具體的類中可以定義多個(gè)初始化代碼塊,在執(zhí)行的時(shí)候按照他們?cè)诖a中的位置順序被調(diào)用,如下面的代碼所示:
package com.javacodegeeks.advanced.construction; public class InitializationBlocks { { // initialization code here } { // initialization code here } }
實(shí)始化代碼塊并不是為了取代構(gòu)造方法,相反它們可以同時(shí)出現(xiàn)。但是要記住,初始化代碼快會(huì)在構(gòu)造方法調(diào)用之前被執(zhí)行。
package com.javacodegeeks.advanced.construction; public class InitializationBlockAndConstructor { { // initialization code here } public InitializationBlockAndConstructor() { } }2.5 保證構(gòu)造默認(rèn)值
Java提供了確定的初始化保證,程序員可以直接使用初始化結(jié)果。未初始化的實(shí)例以及類變量(static)會(huì)自動(dòng)初始化為相應(yīng)的默認(rèn)值。
類型 | 默認(rèn)值 |
---|---|
boolean | False |
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
char | u0000 |
float | 0.0f |
double | 0.0d |
對(duì)象引用 | null |
表 1
我們通過下面的例子來驗(yàn)證上表中的默認(rèn)值:
package com.javacodegeeks.advanced.construction; public class InitializationWithDefaults { private boolean booleanMember; private byte byteMember; private short shortMember; private int intMember; private long longMember; private char charMember; private float floatMember; private double doubleMember; private Object referenceMember; public InitializationWithDefaults() { System.out.println( "booleanMember = " + booleanMember ); System.out.println( "byteMember = " + byteMember ); System.out.println( "shortMember = " + shortMember ); System.out.println( "intMember = " + intMember ); System.out.println( "longMember = " + longMember ); System.out.println( "charMember = " + Character.codePointAt( new char[] { charMember }, 0 ) ); System.out.println( "floatMember = " + floatMember ); System.out.println( "doubleMember = " + doubleMember ); System.out.println( "referenceMember = " + referenceMember ); } }
當(dāng)使用new關(guān)鍵字實(shí)例化對(duì)象之后:
final InitializationWithDefaults initializationWithDefaults = new InitializationWithDefaults(),
可從控制臺(tái)中看到輸出結(jié)果如下:
booleanMember = false byteMember = 0 shortMember = 0 intMember = 0 longMember = 0 charMember = 0 floatMember = 0.0 doubleMember = 0.0 referenceMember = null2.6 可見性
構(gòu)造方法遵從Java的可見性規(guī)則,并且可以通過訪問控制修飾符決定在其他類中是否能調(diào)用該構(gòu)造方法。
修飾符 | 包可見性 | 子類可見性 | 公開可見性 |
---|---|---|---|
public | 可見 | 可見 | 可見 |
protected | 可見 | 可見 | 不可見 |
<無修飾符> | 可見 | 不可見 | 不可見 |
private | 不可見 | 不可見 | 不可見 |
表2
2.7 垃圾回收Java(準(zhǔn)確的說是JVM)擁有自動(dòng)的垃圾回收機(jī)制。簡單來講,當(dāng)有新對(duì)象創(chuàng)建時(shí),會(huì)自動(dòng)為其分配內(nèi)在;然后當(dāng)對(duì)象不再被引用后,他們會(huì)被自動(dòng)銷毀,相應(yīng)的內(nèi)存也會(huì)被回收。
Java垃圾回收采用分代回收的機(jī)制,并基于"大多數(shù)對(duì)象生命短暫"的假設(shè)(即在對(duì)象創(chuàng)建之后很快就不會(huì)被再引用,所以可以被安全的銷毀)。大多程序員習(xí)慣性的認(rèn)為Java中對(duì)象創(chuàng)建的效率很低所以要盡可能避免新對(duì)象的創(chuàng)建。事實(shí)上,這種認(rèn)識(shí)是不對(duì)的。在Java中創(chuàng)建對(duì)象的開銷是相當(dāng)?shù)偷模⑶宜俣群芸臁U嬲鷣砭薮箝_銷的是不必要的長期存活的對(duì)象,因此他們最終會(huì)被遷移到老年代,并導(dǎo)致stop-the-world發(fā)生。
2.8 對(duì)象終結(jié)器(Finalizers)前面我們講述的都是構(gòu)造方法和對(duì)象初始化相關(guān)的主題,但還未提及他們的反面:對(duì)象銷毀。主要是因?yàn)镴ava使用垃圾回收機(jī)制來管理對(duì)象的生命周期,所以銷毀不必要的對(duì)象并釋放所需內(nèi)存就成了垃圾回收的職責(zé)了。
不過,Java還是提供了另外一種類似于析構(gòu)函數(shù)的終結(jié)器(finalizer)的特性,擔(dān)任多種資源清理的責(zé)任。Finalizer一般被看作是危險(xiǎn)的事情(因?yàn)樗鼤?huì)帶來多種副作用和性能問題)。通常并不需要finalizer因此要盡量避免使用它(除了極少見的包含大量本地對(duì)象(native objects)的場景)。Java 7中引入的try-with-resources語法和AutoCloseable接口可當(dāng)作finalizer的替代選擇,并可寫出如下簡潔的代碼:
try ( final InputStream in = Files.newInputStream( path ) ) { // code here }3. 靜態(tài)初始化
上面我們學(xué)習(xí)了類實(shí)例的構(gòu)造與初始化,除此之外,Java還支持類級(jí)別的初始化構(gòu)造,稱作靜態(tài)初始化。靜態(tài)初始化與上面介紹的初始化代碼塊類似,只是多了額外的static關(guān)鍵字修飾。需要注意的是靜態(tài)初始化只會(huì)在類加載時(shí)執(zhí)行一次。示例如下:
package com.javacodegeeks.advanced.construction; public class StaticInitializationBlock { static { // static initialization code here } }
與初始化代碼塊類似,可以在類中定義多個(gè)靜態(tài)初始化塊,它們?cè)陬愔械奈恢脹Q定在初始化時(shí)執(zhí)行的順序。示例如下;
package com.javacodegeeks.advanced.construction; public class StaticInitializationBlocks { static { // static initialization code here } static { // static initialization code here } }
因?yàn)殪o態(tài)初始化塊可以被多個(gè)并行執(zhí)行的線程觸發(fā)(當(dāng)類被初始加載時(shí)),JVM運(yùn)行時(shí)保證初始化的代碼以線程安全的方式只被執(zhí)行一次。
4. 構(gòu)造器模式這些年多種容易理解的構(gòu)造器(創(chuàng)建者)模式被引入到Java社區(qū)。下面我們會(huì)學(xué)習(xí)其中比較流行的幾個(gè):單例模式、輔助類模式、工廠模式以及依賴注入(也稱為控制反轉(zhuǎn))。
4.1 單例模式單例是一種歷史悠久卻在軟件開發(fā)社區(qū)中飽受爭議的模式。單例模式的核心理念是保證在任何時(shí)候給定的類只有一個(gè)對(duì)象被創(chuàng)建。雖然聽起來很簡單,但人們對(duì)如何以正確且線程安全的方式創(chuàng)建對(duì)象進(jìn)行了大量的討論。下面的代碼中展示了簡單版本的單例模式實(shí)現(xiàn):
package com.javacodegeeks.advanced.construction.patterns; public class NaiveSingleton { private static NaiveSingleton instance; private NaiveSingleton() { } public static NaiveSingleton getInstance() { if( instance == null ) { instance = new NaiveSingleton(); } return instance; } }
上面的代碼至少有一個(gè)問題:在多線程并發(fā)場景中可能會(huì)創(chuàng)建出多個(gè)對(duì)象。一種合理的實(shí)現(xiàn)方式(但不能延遲加載)是使用類的static`final`屬性。如下:
final property of the class. package com.javacodegeeks.advanced.construction.patterns; public class EagerSingleton { private static final EagerSingleton instance = new EagerSingleton(); private EagerSingleton() { } public static EagerSingleton getInstance() { return instance; } }
如果你不想浪費(fèi)寶貴的資源,希望單例對(duì)象只在真正需要的時(shí)候才被創(chuàng)建,那么就要使用顯式的同步方式,不可這種方法可能會(huì)降低多線程環(huán)境下的并發(fā)性(更多關(guān)于Java并發(fā)的細(xì)節(jié)將會(huì)在Java進(jìn)階9-并發(fā)最佳實(shí)踐中詳細(xì)介紹)。
package com.javacodegeeks.advanced.construction.patterns; public class LazySingleton { private static LazySingleton instance; private LazySingleton() { } public static synchronized LazySingleton getInstance() { if( instance == null ) { instance = new LazySingleton(); } return instance; } }
現(xiàn)在,在很多場景下單例模式不再被認(rèn)為是一種好的選擇,因?yàn)樗麄儠?huì)使代碼不易于測(cè)試。另外依賴注入模式的產(chǎn)生也使單例模式變得不再必要。
4.2 工具類/輔助類工具類/輔助類模式在Java開發(fā)者當(dāng)中相當(dāng)流行。它的核心理念就是使用不可實(shí)例化的類(通過聲明private構(gòu)造方法)、可選的final(更多關(guān)于聲明final類的細(xì)節(jié)將會(huì)在Java進(jìn)階3-類和接口的設(shè)計(jì)中詳細(xì)介紹)關(guān)鍵字以及靜態(tài)方法。示例如下:
package com.javacodegeeks.advanced.construction.patterns; public final class HelperClass { private HelperClass() { } public static void helperMethod1() { // Method body here } public static void helperMethod2() { // Method body here } }
很多經(jīng)驗(yàn)豐富的開發(fā)者認(rèn)為這種模式會(huì)讓工具類成為各種不相關(guān)方法的容器。因?yàn)橛行┓椒]有合適的放置位置卻需要被其他類使用,就會(huì)被誤放入工具類中。在大多數(shù)場景中也應(yīng)該避免這種設(shè)計(jì):總會(huì)有更好的功能復(fù)用的方式,保持代碼清晰簡潔。
4.3 工廠模式工廠模式被證明是開發(fā)者的極其強(qiáng)大的利器,在Java中有多種實(shí)現(xiàn)方式:工廠方法和抽象工廠。最簡單的例子就是使用static方法返回特定類的實(shí)例(工廠方法),如下:
package com.javacodegeeks.advanced.construction.patterns; public class Book { private Book( final String title) { } public static Book newBook( final String title ) { return new Book( title ); } }
雖然使用這種方法能提高代碼的可讀性,但經(jīng)常爭議的一點(diǎn)是難以給newBook工廠方法賦予更豐富的場景。另外一種實(shí)現(xiàn)工廠模式的方法是采用接口或抽象類(抽象工廠)。如下,我們定義一個(gè)工廠接口:
public interface BookFactory { Book newBook(); }
根據(jù)圖片館的不同,我們可以有多種不同的newBook實(shí)現(xiàn):
public class Library implements BookFactory { @Override public Book newBook() { return new PaperBook(); } } public class KindleLibrary implements BookFactory { @Override public Book newBook() { return new KindleBook(); } }
現(xiàn)在,BookFactory的不同實(shí)現(xiàn)屏蔽掉了具體Book的不同,卻提供了通用的newBook的方法。
4.4 依賴注入依賴注入(也稱為控制反轉(zhuǎn))被類設(shè)計(jì)者認(rèn)為是一種良好的設(shè)計(jì)實(shí)踐:如果一些類實(shí)例依賴其他類的實(shí)例,那些被依賴的實(shí)例應(yīng)該通過構(gòu)造方法(或者setter方法、策略等方式)提供(注入),而不應(yīng)該是由實(shí)例自己去創(chuàng)建。先看一下下面的代碼:
package com.javacodegeeks.advanced.construction.patterns; import java.text.DateFormat; import java.util.Date; public class Dependant { private final DateFormat format = DateFormat.getDateInstance(); public String format( final Date date ) { return format.format( date ); } }
Dependant類需要一個(gè)DateFormat類的實(shí)例并通過在實(shí)例化對(duì)象時(shí)通過DateFormat.getDateInstance()的方式獲得。更好的方式應(yīng)該通過構(gòu)造方法的參數(shù)來完成同樣的事情:
package com.javacodegeeks.advanced.construction.patterns; import java.text.DateFormat; import java.util.Date; public class Dependant { private final DateFormat format; public Dependant( final DateFormat format ) { this.format = format; } public String format( final Date date ) { return format.format( date ); } }
在上面的例子中,類實(shí)例的所有依賴都由外部提供,這樣就很容易調(diào)整DateFormat,并易于編寫測(cè)試代碼。
5. 源碼下載可以從這里下載本文中的源碼:com.javacodegeeks.advanced.java
6. 下章概要在本章中我們學(xué)習(xí)了類及類實(shí)例的構(gòu)造和初始化技術(shù),以及相關(guān)的幾種設(shè)計(jì)模式。下一章中將對(duì)Object類做深入分析,并介紹其中的幾個(gè)重要方法的用法:equals, hashcCode, toString和clone。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/65422.html
摘要:判斷另外一個(gè)對(duì)象是否與當(dāng)前對(duì)象相等返回當(dāng)前對(duì)象的哈希值返回一個(gè)表示當(dāng)前對(duì)象的字符串喚醒一個(gè)等待當(dāng)前對(duì)象的鎖監(jiān)視器的線程。 原文鏈接:http://www.javacodegeeks.com/2015/09/using-methods-common-to-all-objects.html 本文是Java進(jìn)階課程的第二篇。 本課程的目標(biāo)是幫你更有效的使用Java。其中討論了一些高級(jí)主題,包...
摘要:無限期等待另一個(gè)線程執(zhí)行特定操作。線程安全基本版請(qǐng)說明以及的區(qū)別值都不能為空數(shù)組結(jié)構(gòu)上,通過數(shù)組和鏈表實(shí)現(xiàn)。優(yōu)先考慮響應(yīng)中斷,而不是響應(yīng)鎖的普通獲取或重入獲取。只是在最后獲取鎖成功后再把當(dāng)前線程置為狀態(tài)然后再中斷線程。 前段時(shí)間在慕課網(wǎng)直播上聽小馬哥面試勸退(面試虐我千百遍,Java 并發(fā)真討厭),發(fā)現(xiàn)講得東西比自己拿到offer還要高興,于是自己在線下做了一點(diǎn)小筆記,供各位參考。 課...
摘要:使用上一篇文章的例子來說明下自由變量進(jìn)階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數(shù),也不是局部變量,所以是自由變量。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周正式開始前端進(jìn)階的第二期,本周的主題是作用域閉包,今天是第7天。 本計(jì)劃一共28期,每期重點(diǎn)攻克一個(gè)面試重難點(diǎn),如果你還不了解本進(jìn)階計(jì)...
摘要:問題是這些服務(wù)都是第三方提供的,不能保證它們的響應(yīng)時(shí)間,快的話美團(tuán)點(diǎn)評(píng)分布式生成系統(tǒng)后端掘金背景在復(fù)雜分布式系統(tǒng)中,往往需要對(duì)大量的數(shù)據(jù)和消息進(jìn)行唯一標(biāo)識(shí)。 SpringBatch 讀取 txt 文件并寫入數(shù)據(jù)庫 - 后端 - 掘金SpringBatch 讀取 txt 文件并寫入數(shù)據(jù)庫... Java 進(jìn)階-多線程開發(fā)關(guān)鍵技術(shù) - 后端 - 掘金原創(chuàng)文章,轉(zhuǎn)載請(qǐng)務(wù)必將下面這段話置于文章...
摘要:問題是這些服務(wù)都是第三方提供的,不能保證它們的響應(yīng)時(shí)間,快的話美團(tuán)點(diǎn)評(píng)分布式生成系統(tǒng)后端掘金背景在復(fù)雜分布式系統(tǒng)中,往往需要對(duì)大量的數(shù)據(jù)和消息進(jìn)行唯一標(biāo)識(shí)。 SpringBatch 讀取 txt 文件并寫入數(shù)據(jù)庫 - 后端 - 掘金SpringBatch 讀取 txt 文件并寫入數(shù)據(jù)庫... Java 進(jìn)階-多線程開發(fā)關(guān)鍵技術(shù) - 后端 - 掘金原創(chuàng)文章,轉(zhuǎn)載請(qǐng)務(wù)必將下面這段話置于文章...
閱讀 3565·2023-04-25 14:20
閱讀 1178·2021-09-10 10:51
閱讀 1145·2019-08-30 15:53
閱讀 452·2019-08-30 15:43
閱讀 2307·2019-08-30 14:13
閱讀 2784·2019-08-30 12:45
閱讀 1198·2019-08-29 16:18
閱讀 1154·2019-08-29 16:12