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