亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

創(chuàng)建一個Java的不可變對象

 更新時間:2021年11月10日 11:25:35   作者:沉默王二  
這篇文章主要介紹了創(chuàng)建一個Java的不可變對象,一個類的對象在通過構(gòu)造方法創(chuàng)建后如果狀態(tài)不會再被改變,那么它就是一個不可變(immutable)類。它的所有成員變量的賦值僅在構(gòu)造方法中完成,不會提供任何 setter 方法供外部類去修改,需要的朋友可以參考下

前言:

為什么 String immutable 類(不可變對象)嗎?我想研究它,想知道為什么它就不可變了,這種強(qiáng)烈的愿望就像想研究浩瀚的星空一樣。但無奈自身功力有限,始終覺得霧里看花終隔一層。二哥你的文章總是充滿趣味性,我想一定能夠說明白,我也一定能夠看明白,能在接下來寫一寫嗎?

https://github.com/itwanger/toBeBetterJavaer

01、什么是不可變類

一個類的對象在通過構(gòu)造方法創(chuàng)建后如果狀態(tài)不會再被改變,那么它就是一個不可變(immutable)類。它的所有成員變量的賦值僅在構(gòu)造方法中完成,不會提供任何 setter 方法供外部類去修改。

還記得《神雕俠侶》中小龍女的古墓嗎?隨著那一聲巨響,僅有的通道就被無情地關(guān)閉了。別較真那個密道,我這么說只是為了打開你的想象力,讓你對不可變類有一個更直觀的印象。

自從有了多線程,生產(chǎn)力就被無限地放大了,所有的程序員都愛它,因為強(qiáng)大的硬件能力被充分地利用了。但與此同時,所有的程序員都對它心生忌憚,因為一不小心,多線程就會把對象的狀態(tài)變得混亂不堪。

為了保護(hù)狀態(tài)的原子性、可見性、有序性,我們程序員可以說是竭盡所能。其中,synchronized(同步)關(guān)鍵字是最簡單最入門的一種解決方案。

假如說類是不可變的,那么對象的狀態(tài)就也是不可變的。這樣的話,每次修改對象的狀態(tài),就會產(chǎn)生一個新的對象供不同的線程使用,我們程序員就不必再擔(dān)心并發(fā)問題了。

02、常見的不可變類

提到不可變類,幾乎所有的程序員第一個想到的,就是 String 類。那為什么 String 類要被設(shè)計成不可變的呢?

1)常量池的需要

字符串常量池是 Java 堆內(nèi)存中一個特殊的存儲區(qū)域,當(dāng)創(chuàng)建一個 String 對象時,假如此字符串在常量池中不存在,那么就創(chuàng)建一個;假如已經(jīng)存,就不會再創(chuàng)建了,而是直接引用已經(jīng)存在的對象。這樣做能夠減少 JVM 的內(nèi)存開銷,提高效率。

2)hashCode 的需要

因為字符串是不可變的,所以在它創(chuàng)建的時候,其 hashCode 就被緩存了,因此非常適合作為哈希值(比如說作為 HashMap 的鍵),多次調(diào)用只返回同一個值,來提高效率。

3)線程安全

就像之前說的那樣,如果對象的狀態(tài)是可變的,那么在多線程環(huán)境下,就很容易造成不可預(yù)期的結(jié)果。而 String 是不可變的,就可以在多個線程之間共享,不需要同步處理。

因此,當(dāng)我們調(diào)用 String 類的任何方法(比如說 trim()substring() 、toLowerCase())時,總會返回一個新的對象,而不影響之前的值。

String cmower = "沉默王二,一枚有趣的程序員"; 
cmower.substring(0,4); 
System.out.println(cmower);// 沉默王二,一枚有趣的程序員 

雖然調(diào)用 substring() 方法對 cmower 進(jìn)行了截取,但 cmower 的值沒有改變。

除了 String 類,包裝器類 Integer、Long 等也是不可變類。

03、手?jǐn)]不可變類

看懂一個不可變類也許容易,但要創(chuàng)建一個自定義的不可變類恐怕就有點難了。但知難而進(jìn)是我們作為一名優(yōu)秀的程序員不可或缺的品質(zhì),正因為不容易,我們才能真正地掌握它。

接下來,就請和我一起,來自定義一個不可變類吧。一個不可變誒,必須要滿足以下 4 個條件:

  • 1)確保類是 final 的,不允許被其他類繼承。
  • 2)確保所有的成員變量(字段)是 final 的,這樣的話,它們就只能在構(gòu)造方法中初始化值,并且不會在隨后被修改。
  • 3)不要提供任何 setter 方法。
  • 4)如果要修改類的狀態(tài),必須返回一個新的對象。

按照以上條件,我們來自定義一個簡單的不可變類 Writer。

public final class Writer { 
    private final String name; 
    private final int age; 
 
    public Writer(String name, int age) { 
        this.name = name; 
        this.age = age; 
    } 
 
    public int getAge() { 
        return age; 
    } 
 
    public String getName() { 
        return name; 
    } 
} 


Writer 類是 final 的,name age 也是 final 的,沒有 setter 方法。

OK,據(jù)說這個作者分享了很多博客,廣受讀者的喜愛,因此某某出版社找他寫了一本書(Book)。Book 類是這樣定義的:

public class Book { 
    private String name; 
    private int price; 
 
    public String getName() { 
        return name; 
    } 
 
    public void setName(String name) { 
        this.name = name; 
    } 
 
    public int getPrice() { 
        return price; 
    } 
 
    public void setPrice(int price) { 
        this.price = price; 
    } 
 
    @Override 
    public String toString() { 
        return "Book{" + 
                "name='" + name + '\'' + 
                ", price=" + price + 
                '}'; 
    } 
} 


2 個字段,分別是 name price,以及 getter setter,重寫后的 toString() 方法。然后,在 Writer 類中追加一個可變對象字段 book。

public final class Writer { 
    private final String name; 
    private final int age; 
    private final Book book; 
 
    public Writer(String name, int age, Book book) { 
        this.name = name; 
        this.age = age; 
        this.book = book; 
    } 
 
    public int getAge() { 
        return age; 
    } 
 
    public String getName() { 
        return name; 
    } 
 
    public Book getBook() { 
        return book; 
    } 
} 


并在構(gòu)造方法中追加了 Book 參數(shù),以及 Book getter 方法。

完成以上工作后,我們來新建一個測試類,看看 Writer 類的狀態(tài)是否真的不可變。

public class WriterDemo { 
    public static void main(String[] args) { 
        Book book = new Book(); 
        book.setName("Web全棧開發(fā)進(jìn)階之路"); 
        book.setPrice(79); 
 
        Writer writer = new Writer("沉默王二",18, book); 
        System.out.println("定價:" + writer.getBook()); 
        writer.getBook().setPrice(59); 
        System.out.println("促銷價:" + writer.getBook()); 
    } 
} 

程序輸出的結(jié)果如下所示:

定價:Book{name='Web全棧開發(fā)進(jìn)階之路', price=79}
促銷價:Book{name='Web全棧開發(fā)進(jìn)階之路', price=59}

糟糕,Writer 類的不可變性被破壞了,價格發(fā)生了變化。為了解決這個問題,我們需要為不可變類的定義規(guī)則追加一條內(nèi)容:

如果一個不可變類中包含了可變類的對象,那么就需要確保返回的是可變對象的副本。也就是說,Writer 類中的 getBook() 方法應(yīng)該修改為:

public Book getBook() { 
    Book clone = new Book(); 
    clone.setPrice(this.book.getPrice()); 
    clone.setName(this.book.getName()); 
    return clone; 
} 

這樣的話,構(gòu)造方法初始化后的 Book 對象就不會再被修改了。此時,運行 WriterDemo,就會發(fā)現(xiàn)價格不再發(fā)生變化了。

定價:Book{name='Web全棧開發(fā)進(jìn)階之路', price=79}
促銷價:Book{name='Web全棧開發(fā)進(jìn)階之路', price=79}

04、總結(jié)

不可變類有很多優(yōu)點,就像之前提到的 String 類那樣,尤其是在多線程環(huán)境下,它非常的安全。盡管每次修改都會創(chuàng)建一個新的對象,增加了內(nèi)存的消耗,但這個缺點相比它帶來的優(yōu)點,顯然是微不足道的——無非就是撿了西瓜,丟了芝麻。

到此這篇關(guān)于創(chuàng)建一個Java的不可變對象的文章就介紹到這了,更多相關(guān)Java的不可變對象內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java編程思想里的泛型實現(xiàn)一個堆棧類 分享

    Java編程思想里的泛型實現(xiàn)一個堆棧類 分享

    這篇文章介紹了Java編程思想里的泛型實現(xiàn)一個堆棧類,有需要的朋友可以參考一下
    2013-07-07
  • SpringBoot整合Swagger2的示例

    SpringBoot整合Swagger2的示例

    這篇文章主要介紹了SpringBoot整合Swagger2的示例,幫助大家更好的理解和學(xué)習(xí)springboot框架,感興趣的朋友可以了解下
    2020-11-11
  • 圖解JVM垃圾內(nèi)存回收算法

    圖解JVM垃圾內(nèi)存回收算法

    這篇文章主要介紹了圖解JVM垃圾內(nèi)存回收算法,由于年輕代堆空間的垃圾回收會很頻繁,因此其垃圾回收算法會更加重視回收效率,下面小編就和大家來一起學(xué)習(xí)一下吧
    2019-06-06
  • gateway與spring-boot-starter-web沖突問題的解決

    gateway與spring-boot-starter-web沖突問題的解決

    這篇文章主要介紹了gateway與spring-boot-starter-web沖突問題的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • Java SpringMVC自學(xué)自講

    Java SpringMVC自學(xué)自講

    本篇文章主要介紹了java SpringMVC——如何獲取請求參數(shù)詳解,詳細(xì)的介紹了每種參數(shù)注解的用法及其實例。感興趣的小伙伴們可以參考一下
    2021-09-09
  • 手?jǐn)]一個 spring-boot-starter的全過程

    手?jǐn)]一個 spring-boot-starter的全過程

    這篇文章主要介紹了手?jǐn)]一個 spring-boot-starter的全過程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • Springcloud Stream消息驅(qū)動工具使用介紹

    Springcloud Stream消息驅(qū)動工具使用介紹

    SpringCloud Stream由一個中間件中立的核組成,應(yīng)用通過SpringCloud Stream插入的input(相當(dāng)于消費者consumer,它是從隊列中接收消息的)和output(相當(dāng)于生產(chǎn)者producer,它是發(fā)送消息到隊列中的)通道與外界交流
    2022-09-09
  • Java Volatile 變量詳解及使用方法

    Java Volatile 變量詳解及使用方法

    這篇文章主要介紹了Java Volatile 變量詳解及使用方法的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Java動態(tài)代理模式的深入揭秘

    Java動態(tài)代理模式的深入揭秘

    這篇文章主要給大家介紹了關(guān)于Java動態(tài)代理模式的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • JDK1.6“新“特性Instrumentation之JavaAgent(推薦)

    JDK1.6“新“特性Instrumentation之JavaAgent(推薦)

    這篇文章主要介紹了JDK1.6“新“特性Instrumentation之JavaAgent,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08

最新評論