<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何正確的創(chuàng)建和銷(xiāo)毀Java對(duì)象

          共 14423字,需瀏覽 29分鐘

           ·

          2021-09-22 09:59

          點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)

          一、介紹

          Java由Sun Microsystems發(fā)明并在1995年發(fā)布,是世界上使用最廣泛的編程語(yǔ)言之一。Java是一個(gè)通用編程語(yǔ)言。由于它擁有功能強(qiáng)大的庫(kù)、運(yùn)行時(shí)、簡(jiǎn)單的語(yǔ)法、平臺(tái)無(wú)關(guān)(Write Once, Run Anywhere - WORA)以及令人敬畏的社區(qū)從而吸引了很多的開(kāi)發(fā)者。

          本系列文章我們我們將會(huì)覆蓋一些高級(jí)的Java概念,我們假設(shè)你對(duì)Java語(yǔ)言已經(jīng)有一些基礎(chǔ)知識(shí)。本系列文章并不是一個(gè)完整的參考,而是一個(gè)將您的Java技能提升到下一個(gè)級(jí)別的詳細(xì)指南。

          本系列文章中將會(huì)看到一些代碼片段,在這些代碼片段里面將會(huì)使用java 7的語(yǔ)法以及java 8的語(yǔ)法。

          二、實(shí)例構(gòu)造(Instance Construction)

          Java是面向?qū)ο蟮木幊陶Z(yǔ)言,所以新實(shí)例(objects)的創(chuàng)建可能是它最重要的概念之一。在新的類(lèi)實(shí)例中構(gòu)造器(Constructors)扮演了非常核心的角色,Java對(duì)于構(gòu)造器(Constructors)的定義提供了很多方案。

          2.1 隱式(implicitly)構(gòu)造器

          Java允許定義無(wú)任何構(gòu)造器的類(lèi),但是這并不意味著此類(lèi)沒(méi)有構(gòu)造器。比如說(shuō),讓我們看一下下面這個(gè)類(lèi)。

          package com.javacodegeeks.advanced.construction;
          public class NoConstructor {
          }

          此類(lèi)沒(méi)有構(gòu)造器,但是Java編譯器會(huì)隱式地(implicitly)生成一個(gè)構(gòu)造器并且在使用new關(guān)鍵字創(chuàng)建新的類(lèi)實(shí)例時(shí)會(huì)被調(diào)用。

          final NoConstructor noConstructorInstance = new NoConstructor();

          2.2 無(wú)參構(gòu)造器(Constructors without Arguments)

          無(wú)參構(gòu)造器是顯式執(zhí)行Java編譯器工作的最簡(jiǎn)單的方法。

          package com.javacodegeeks.advanced.construction;
          public class NoArgConstructor {
              public NoArgConstructor() {
                  // Constructor body here
              }
          }

          在使用new關(guān)鍵字創(chuàng)建此類(lèi)的新實(shí)例時(shí)會(huì)此構(gòu)造器將會(huì)被調(diào)用。

          final NoArgConstructor noArgConstructor = new NoArgConstructor();

          2.3 有參構(gòu)造器(Constructors with Arguments)

          有參構(gòu)造器是參數(shù)化創(chuàng)建類(lèi)實(shí)例的一個(gè)非常有意思和有用的方法。下面這個(gè)類(lèi)定義了一個(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)建類(lèi)實(shí)例時(shí),兩個(gè)構(gòu)造參數(shù)都必須提供。

          final ConstructorWithArguments constructorWithArguments = new ConstructorWithArguments( "arg1""arg2" );

          非常有意思的是,使用this關(guān)鍵字,構(gòu)造器之間可以相互調(diào)用。這種連接構(gòu)造函數(shù)的方式在作為減少代碼重復(fù)方面是一個(gè)非常好的實(shí)踐,并且從跟本上說(shuō)這樣做可以讓一個(gè)類(lèi)只有一個(gè)初始化入口點(diǎn)。接上例,我們添加一個(gè)只有一個(gè)參數(shù)的構(gòu)造器。

          public ConstructorWithArguments(final String arg1) {
          this(arg1, null);
          }

          2.4 初始化塊(Initialization Blocks)

          Java也提供了另外一種使用初始化塊的方式實(shí)現(xiàn)初始化邏輯。這個(gè)特性很少使用但是非常有必要了解一下它的存在。

          package com.javacodegeeks.advanced.construction;
              public class InitializationBlock {
              {
                  // initialization code here
              }
          }

          在某些情況下,初始化塊可以彌補(bǔ)匿名無(wú)參構(gòu)造器的缺陷。有一些特殊的類(lèi)可能會(huì)有很多個(gè)初始化塊并且他們會(huì)依次按照他們?cè)诖a中定義的順序被調(diào)用,比如:

          package com.javacodegeeks.advanced.construction;
          public class InitializationBlocks {
              {
                  // initialization code here
              } {
                  // initialization code here
              }
          }

          初始化塊并不是替代構(gòu)造器并且他們可以獨(dú)立于構(gòu)造器而存在。但是需要提及的最重要的一點(diǎn)就是初始化塊會(huì)在任何構(gòu)造器被調(diào)用之前被執(zhí)行。

          package com.javacodegeeks.advanced.construction;
          public class InitializationBlockAndConstructor {
              {
                  // initialization code here
              }
              public InitializationBlockAndConstructor() {
              }
          }

          2.5 構(gòu)造保障(Construction guarantee)

          Java提供了一些開(kāi)發(fā)者所依賴(lài)的初始化保障,未初始化的實(shí)例和類(lèi)參數(shù)會(huì)自動(dòng)初始化為它們的默認(rèn)值。

          圖片

          讓我們使用下面的例子來(lái)確認(rè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 );
              }
          }

          一旦使用new關(guān)鍵字實(shí)例化:

          inal InitializationWithDefaults initializationWithDefaults = new InitializationWithDefaults();

          將會(huì)在控制臺(tái)輸出如下結(jié)果:

          booleanMember = false
          byteMember = 0
          shortMember = 0
          intMember = 0
          longMember = 0
          charMember = 0
          floatMember = 0.0
          doubleMember = 0.0
          referenceMember = null

          2.6 可見(jiàn)性(Visibility)

          構(gòu)造器受Java可見(jiàn)性規(guī)則約束并且可以擁有訪問(wèn)控制修飾符來(lái)決定是否其他類(lèi)可以調(diào)用特定的構(gòu)造函數(shù)。

          圖片

          2.7 垃圾回收(Garbage collection)

          Java(特別是JVM)使用自動(dòng)垃圾回收機(jī)制。簡(jiǎn)而言之,當(dāng)新對(duì)象被創(chuàng)建,JVM就會(huì)自動(dòng)為這些新創(chuàng)建的對(duì)象分配內(nèi)存。于是,當(dāng)這些對(duì)象沒(méi)有任何引用的時(shí)候,他們就會(huì)被銷(xiāo)毀并且他們所占用的內(nèi)存就會(huì)被回收。

          Java垃圾回收是分代的,基于這種假設(shè)(分代假設(shè))大多數(shù)的對(duì)象在很年輕的時(shí)候就已經(jīng)不可達(dá)(在他們被創(chuàng)建之后的很短的時(shí)間內(nèi)就沒(méi)有任何引用并且被安全銷(xiāo)毀)。大多數(shù)開(kāi)發(fā)者曾經(jīng)相信在Java中創(chuàng)建對(duì)象是很慢的并且應(yīng)該盡可能地避免新對(duì)象的實(shí)例化。

          實(shí)際上,這并不成立:在Java中創(chuàng)建對(duì)象的開(kāi)銷(xiāo)非常的小并且很快。雖然如此,但是沒(méi)有必要?jiǎng)?chuàng)建生命周期比較長(zhǎng)的對(duì)象,因?yàn)閯?chuàng)建過(guò)多的長(zhǎng)壽命對(duì)象最終可能會(huì)填滿(mǎn)老年代空間從而引發(fā)stop-the-world的垃圾回收,這樣的話開(kāi)銷(xiāo)就會(huì)比較大。

          2.8 終結(jié)器(Finalizers)

          到目前為止,我們已經(jīng)談到了構(gòu)造函數(shù)和對(duì)象初始化,但實(shí)際上并沒(méi)有提到任何關(guān)于對(duì)象銷(xiāo)毀的內(nèi)容。這是因?yàn)镴ava使用垃圾收集器去管理對(duì)象的生命周期,并且垃圾收集器的責(zé)任就是去銷(xiāo)毀無(wú)用對(duì)象并回收這些對(duì)象占用的內(nèi)存。

          然而,在Java中有一個(gè)被稱(chēng)為終結(jié)器(Finalizers)的特殊特性,它有點(diǎn)類(lèi)似于析構(gòu)函數(shù),但是在執(zhí)行資源清理時(shí)它所解決的是不同的意圖。終結(jié)器(Finalizers)是被考慮用來(lái)解決一些危險(xiǎn)的特征(比如會(huì)導(dǎo)致無(wú)數(shù)的副作用和性能問(wèn)題的問(wèn)題)。

          一般來(lái)說(shuō),他們是沒(méi)有必要的,應(yīng)該避免(除了非常罕見(jiàn)的情況下,主要是有關(guān)本地對(duì)象)。Java 7語(yǔ)言引入了一種名為try-with-resources的更好的替代方法和AutoCloseable接口,它允許像如下的方式這樣干凈的寫(xiě)代碼:

          try ( final InputStream in = Files.newInputStream( path ) ) {
              // code here
          }

          3、靜態(tài)初始化(Static initialization)

          到目前為止,,我們已經(jīng)談到了構(gòu)造函數(shù)和對(duì)象初始化。但是Java也支持類(lèi)級(jí)別的初始化構(gòu)造,我們稱(chēng)之為靜態(tài)初始化(Static initialization)。

          靜態(tài)初始化(Static initialization)有點(diǎn)類(lèi)似于初始化塊,除了需要添加static關(guān)鍵字之外。注意靜態(tài)初始化在每次類(lèi)加載的時(shí)候它只執(zhí)行一次。比如:

          package com.javacodegeeks.advanced.construction;
          public class StaticInitializationBlock {
              static {
                  // static initialization code here
              }
          }

          和初始化塊類(lèi)似,在類(lèi)定義時(shí)你可以包含任意數(shù)量的初始化塊,它們會(huì)根據(jù)在類(lèi)代碼中出現(xiàn)的順序依次執(zhí)行,比如:

          package com.javacodegeeks.advanced.construction;
          public class StaticInitializationBlocks {
              static {
                  // static initialization code here
              }
              static {
                  // static initialization code here
              }
          }

          因?yàn)殪o態(tài)初始化(Static initialization)塊可以從多個(gè)并行線程中觸發(fā)(第一次類(lèi)加載發(fā)生),Java運(yùn)行時(shí)保證在線程安全的前提下僅僅被執(zhí)行一次。

          4、構(gòu)造模式(Construction Patterns)

          過(guò)去這幾年很多易于理解和廣泛應(yīng)用的構(gòu)造模式在Java社區(qū)出現(xiàn)。我們將會(huì)介紹幾個(gè)比較常用的:?jiǎn)卫J剑╯ingleton)、幫助器(helpers)、工廠模式(factory)、依賴(lài)注入(dependency injection )——大家熟知的控制反轉(zhuǎn)(inversion of control)。

          4.1 單例模式(Singleton)

          單例模式是軟件開(kāi)發(fā)者社區(qū)中最老也是最具爭(zhēng)議性的模式之一?;緛?lái)說(shuō),它的主要思想就是確保在任何時(shí)候類(lèi)僅僅只有一個(gè)實(shí)例被創(chuàng)建。思想就是如此簡(jiǎn)單,然而單例模式引發(fā)了很多關(guā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è)問(wèn)題就是如果多個(gè)線程同時(shí)調(diào)用,那么此類(lèi)就能夠創(chuàng)建多個(gè)實(shí)例。設(shè)計(jì)合適的單例模式的方法之一是使用類(lèi)的 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)建的話,這就要求顯示同步了(explicit synchronization),這就有可能導(dǎo)致多線程環(huán)境中的并發(fā)性降低(關(guān)于并發(fā)的詳細(xì)內(nèi)容我們將會(huì)在后續(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;
              }
          }

          如今,在大多數(shù)的案例中單例模式并不被考慮作為一個(gè)很好的選擇,主要是因?yàn)閱卫J綄?huì)導(dǎo)致代碼很難測(cè)試。依賴(lài)注入模式讓單例模式變得沒(méi)有必要。

          4.2 Utility/Helper類(lèi)

          utility或者h(yuǎn)elper類(lèi)是被許多開(kāi)發(fā)者所使用的相當(dāng)流行的一種模式?;緛?lái)說(shuō),它所代表的是無(wú)實(shí)例( non-instantiable)類(lèi)(構(gòu)造器被定義成private),僅僅可以選擇將方法定義成final(后續(xù)會(huì)介紹如何定義類(lèi))或者static。比如;

          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
              }
          }

          站在開(kāi)發(fā)者的角度,helpers類(lèi)經(jīng)常所扮演的是一個(gè)容器的角色,這個(gè)容器中放了很多在其他地方找不到但是其他類(lèi)需要相互共享和使用的互相不相關(guān)的方法。這種設(shè)計(jì)決定了在很多情況下要避免使用:總能找到另一種重用所需功能的方式,保持代碼的簡(jiǎn)潔和清晰。

          4.3 工廠模式(Factory)

          工廠模式被證明是軟件開(kāi)發(fā)人員手中非常有用的技術(shù)。因此,Java有幾種風(fēng)格工廠模式,從工廠方法到抽象工廠。工廠模式最簡(jiǎn)單的例子是返回特定類(lèi)的新實(shí)例的靜態(tài)方法(工廠方法)。例如:

          package com.javacodegeeks.advanced.construction.patterns;
          public class Book {
              private Bookfinal String title) {
              }
              public static Book newBookfinal String title ) {
                  return new Book( title );
              }
          }

          有人可能會(huì)爭(zhēng)辯說(shuō),介紹newBook工廠方法并沒(méi)有什么意義,但是使用這種模式通常會(huì)使代碼更具可讀性。工廠模式的另一個(gè)變化涉及接口或抽象類(lèi)(抽象工廠)。例如,讓我們定義一個(gè)工廠接口:

          public interface BookFactory {
              Book newBook();
          }

          依賴(lài)庫(kù)類(lèi)型,完成幾種不同的實(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)在,Book的特定類(lèi)被隱藏在BookFactory接口實(shí)現(xiàn)之后,BookFactory仍然提供創(chuàng)建book的通用方式。

          4.4 依賴(lài)注入(Dependency Injection)

          依賴(lài)注入(一說(shuō)控制反轉(zhuǎn))被類(lèi)設(shè)計(jì)者認(rèn)為是一個(gè)很好的做法:如果某些類(lèi)的實(shí)例依賴(lài)其他類(lèi)的實(shí)例,被依賴(lài)的實(shí)例應(yīng)該通過(guò)構(gòu)造(比如通過(guò)設(shè)置器——setters,或者策略——strategies模式等)的思想提供給依賴(lài)的實(shí)例,而不是依賴(lài)的實(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 formatfinal Date date ) {
                  return format.format( date );
              }
          }

          類(lèi)Dependant需要一個(gè)DateFormat的實(shí)例,并且它僅僅只是在構(gòu)造時(shí)通過(guò)調(diào)用DateFormat.getDateInstance() 創(chuàng)建。最好的設(shè)計(jì)方案應(yīng)該是通過(guò)構(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 Dependantfinal DateFormat format ) {
                  this.format = format;
              }


              public String formatfinal Date date ) {
                  return format.format( date );
              }
          }

          按這種方案實(shí)現(xiàn)的話,類(lèi)的所有依賴(lài)都是通過(guò)外部提供,這樣就很容易的修改date format和為類(lèi)寫(xiě)測(cè)試用例。

          在本系列文章的這一部分中,我們一直在研究類(lèi)和類(lèi)的實(shí)例構(gòu)造以及初始化技術(shù),涵蓋了幾種廣泛使用的模式。在下一部分中,我們將分析Object類(lèi)以及其熟知方法的用法:equals,hashCode,toString和clone。

          (感謝閱讀,希望對(duì)你所有幫助)
          來(lái)源:blog.csdn.net/zyhlwzy/article/details/78937421

          1、靈魂一問(wèn):你的登錄接口真的安全嗎?

          2、HashMap 中這些設(shè)計(jì),絕了~

          3、在 IntelliJ IDEA 中這樣使用 Git,賊方便了!

          4、計(jì)算機(jī)時(shí)間到底是怎么來(lái)的?程序員必看的時(shí)間知識(shí)!

          5、這些IDEA的優(yōu)化設(shè)置趕緊安排起來(lái),效率提升杠杠的!

          6、21 款 yyds 的 IDEA插件

          7、真香!用 IDEA 神器看源碼,效率真高!

          點(diǎn)分享

          點(diǎn)收藏

          點(diǎn)點(diǎn)贊

          點(diǎn)在看

          瀏覽 37
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  安去也在线观看免费 | 射无码在线 | 国产操P| 日逼综合网 | 国产精品久久久久久久久动漫 |