不可變對象
如果一個對象的狀態(tài)在構(gòu)造后不能改變,則該對象被認(rèn)為是不可變的,對不可變對象的最大依賴被廣泛認(rèn)為是一種創(chuàng)建簡單、可靠代碼的合理策略。
不可變對象在并發(fā)應(yīng)用程序中特別有用,由于它們不能改變狀態(tài),因此它們不會被線程干擾破壞或在不一致的狀態(tài)下觀察。
程序員通常不愿意使用不可變對象,因為他們擔(dān)心創(chuàng)建新對象的成本而不是就地更新對象的成本,對象創(chuàng)建的影響經(jīng)常被高估,并且可以通過與不可變對象相關(guān)聯(lián)的一些效率來抵消,這些包括由于垃圾收集而減少的開銷,以及消除保護(hù)可變對象免于損壞所需的代碼。
以下小節(jié)采用其實例可變的類,并從中派生出具有不可變實例的類,通過這樣做,它們?yōu)檫@種轉(zhuǎn)換提供了一般規(guī)則,并演示了不可變對象的一些優(yōu)點。
同步類示例SynchronizedRGB類定義了表示顏色的對象,每個對象將顏色表示為代表主要顏色值的三個整數(shù)和一個給出顏色名稱的字符串。
public class SynchronizedRGB { // Values must be between 0 and 255. private int red; private int green; private int blue; private String name; private void check(int red, int green, int blue) { if (red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) { throw new IllegalArgumentException(); } } public SynchronizedRGB(int red, int green, int blue, String name) { check(red, green, blue); this.red = red; this.green = green; this.blue = blue; this.name = name; } public void set(int red, int green, int blue, String name) { check(red, green, blue); synchronized (this) { this.red = red; this.green = green; this.blue = blue; this.name = name; } } public synchronized int getRGB() { return ((red << 16) | (green << 8) | blue); } public synchronized String getName() { return name; } public synchronized void invert() { red = 255 - red; green = 255 - green; blue = 255 - blue; name = "Inverse of " + name; } }
必須小心使用SynchronizedRGB以避免在不一致的狀態(tài)下被查看,例如,假設(shè)一個線程執(zhí)行以下代碼:
SynchronizedRGB color = new SynchronizedRGB(0, 0, 0, "Pitch Black"); ... int myColorInt = color.getRGB(); //Statement 1 String myColorName = color.getName(); //Statement 2
如果另一個線程在語句1之后但在語句2之前調(diào)用color.set,則myColorInt的值將與myColorName的值不匹配,為了避免這種結(jié)果,必須將兩個語句綁定在一起:
synchronized (color) { int myColorInt = color.getRGB(); String myColorName = color.getName(); }
這種不一致只適用于可變對象 — 對于不可變版本的SynchronizedRGB,它不會是一個問題。
一種定義不可變對象的策略以下規(guī)則定義了用于創(chuàng)建不可變對象的簡單策略,并非所有記錄為“不可變”的類都遵循這些規(guī)則。這并不一定意味著這些類的創(chuàng)造者是草率的 — 他們可能有充分的理由相信他們類的實例在構(gòu)造后永遠(yuǎn)不會改變,但是,這種策略需要復(fù)雜的分析,不適合初學(xué)者。
不要提供“setter”方法 — 修改字段或字段引用的對象的方法。
使所有字段為final和private。
不允許子類重寫方法,最簡單的方法是將類聲明為final,更復(fù)雜的方法是使構(gòu)造函數(shù)為private并在工廠方法中構(gòu)造實例。
如果實例字段包含對可變對象的引用,則不允許更改這些對象:
不要提供修改可變對象的方法。
不要共享對可變對象的引用,永遠(yuǎn)不要存儲對傳遞給構(gòu)造函數(shù)的外部可變對象的引用,如有必要,創(chuàng)建副本并存儲對副本的引用,同樣,必要時創(chuàng)建內(nèi)部可變對象的副本,以避免在方法中返回原始對象。
將此策略應(yīng)用于SynchronizedRGB會導(dǎo)致以下步驟:
這個類中有兩個setter方法,第一個方法set,任意改變對象,在類的不可變版本中不存在,第二個方法invert,可以通過讓它創(chuàng)建一個新對象而不是修改現(xiàn)有對象來進(jìn)行調(diào)整。
所有字段都已為private,他們進(jìn)一步獲得final。
該類本身被聲明為final。
只有一個字段引用一個對象,該對象本身是不可變的,因此,不需要防止改變“包含的”可變對象的狀態(tài)的保護(hù)措施。
在這些更改之后,我們有ImmutableRGB:
final public class ImmutableRGB { // Values must be between 0 and 255. final private int red; final private int green; final private int blue; final private String name; private void check(int red, int green, int blue) { if (red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255) { throw new IllegalArgumentException(); } } public ImmutableRGB(int red, int green, int blue, String name) { check(red, green, blue); this.red = red; this.green = green; this.blue = blue; this.name = name; } public int getRGB() { return ((red << 16) | (green << 8) | blue); } public String getName() { return name; } public ImmutableRGB invert() { return new ImmutableRGB(255 - red, 255 - green, 255 - blue, "Inverse of " + name); } }上一篇:守護(hù)阻塞
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/73050.html
Date-Time Java SE 8發(fā)行版中引入的Date-Time包java.time提供了全面的日期和時間模型,是在JSR 310:Date and Time API下開發(fā)的,盡管java.time基于國際標(biāo)準(zhǔn)化組織(ISO)日歷系統(tǒng),但也支持常用的全球日歷。 此課程介紹了使用基于ISO的類來表示日期和時間以及操作日期和時間值的基本原理。 概述 時間似乎是一個簡單的主題,即便是便宜的手表也能...
摘要:原文鏈接已于成功發(fā)布,不過目前絕大多數(shù)人在生產(chǎn)環(huán)境仍舊使用的是。這篇以案例為主的教程涵蓋了從到的絕大多數(shù)重要的語法與特性。當(dāng)編譯器不能正確識別出變量的數(shù)值類型時,將不被允許使用。同步請求將會阻塞當(dāng)前的線程,直到返回響應(yīng)消息。 showImg(https://segmentfault.com/img/remote/1460000016575203); 原文鏈接:https://wangw...
摘要:在接下來的分鐘,你將會學(xué)會如何通過同步關(guān)鍵字,鎖和信號量來同步訪問共享可變變量。所以在使用樂觀鎖時,你需要每次在訪問任何共享可變變量之后都要檢查鎖,來確保讀鎖仍然有效。 原文:Java 8 Concurrency Tutorial: Synchronization and Locks譯者:飛龍 協(xié)議:CC BY-NC-SA 4.0 歡迎閱讀我的Java8并發(fā)教程的第二部分。這份指南將...
摘要:創(chuàng)建字符串教程字符串長度用于獲取有關(guān)對象的信息的方法稱為訪問器方法。類在中被提出,它和之間的最大不同在于的方法不是線程安全的不能同步訪問。然而在應(yīng)用程序要求線程安全的情況下,則必須使用類。 一般地,當(dāng)需要使用數(shù)字的時候,我們通常使用內(nèi)置數(shù)據(jù)類型,如:byte、int、long、double 等。 在實際開發(fā)過程中,我們經(jīng)常會遇到需要使用對象,而不是內(nèi)置數(shù)據(jù)類型的情形。為了解決這個問題,...
字符串 在Java編程中廣泛使用的字符串是一系列字符,在Java編程語言中,字符串是對象。 Java平臺提供String類來創(chuàng)建和操作字符串。 創(chuàng)建字符串 創(chuàng)建字符串的最直接方法是編寫: String greeting = Hello world!; 在這種情況下,Hello world!是一個字符串文字 — 代碼中的一系列字符,用雙引號括起來,每當(dāng)它在代碼中遇到字符串文字時,編譯器就會創(chuàng)建一個帶...
閱讀 1761·2021-11-25 09:43
閱讀 1800·2021-11-24 10:41
閱讀 3115·2021-09-27 13:36
閱讀 822·2019-08-30 15:53
閱讀 3584·2019-08-30 15:44
閱讀 874·2019-08-30 14:03
閱讀 2585·2019-08-29 16:38
閱讀 1008·2019-08-29 13:23