Java中建立不可變的類
本文由碼農網 – 栗子蜀黍原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃!
簡介:本文主要介紹java中不可變類的相關知識,文章中大部分內容來自部落格,部落格地址見以下連結
Creating Immutable Classes in Java
小編不去糾結原文中,為什麼標題是immutable class,正文卻上來便問what is immutable object。相信,學java的人,都應該知道class和object確切表示什麼意思。
class:java中class確切的表示為一個類
object:java中object確切的表示為一個物件,也稱為類的例項
其實,如果一個類被設計成不可變的類,那麼這個類的例項化物件也是不可變的。
不可變類:當你獲得這個類的一個例項引用時,你不可以改變這個例項的內容。
那麼,什麼是不可變物件?
一旦一個類的例項化物件被建立並初始化,那麼它就不可以被改變。我們可以呼叫訪問器方法(getter),複製物件,或者傳遞物件,但是不允許任何方法改變這個物件的狀態。包裝類(e.g.Integer或Float)和String類是不可變類的代表。
訪問器方法(accessor method):對成員變數做出訪問的方法,e.g.getter()方法。
修改器方法(mutator method):對成員變數做出修改的方法,e.g.setter()方法。
定義一個不可變類
如果我們要自己建立一個不可變類,需要遵守下面的規則:
將成員變數(field:在一些書中也翻譯為域)宣告成final並在構造器中初始化。
對於基本型別的成員變數,用final修飾,一旦它被初始化,就不能被改變了。而對於引用型別的成員變數,不能夠改變它的引用。
成員變數如果被宣告稱final,那麼構建物件時,必須要初始化這樣的域
引用型別是可變的,我們需要採取一些措施來保證它的不可變性。
為什麼?如果我們只是宣告瞭一個final的可變引用型別,那麼這個引用可以去引用外部的類,或者被其他外部類引用。在這種情況下,我們要做到:
1.這些方法不會改變這些可變物件中的內容
2.不要將這些引用分享到外部供其他類使用,例如,如果對成員變數的引用是可以被其他類改變的,那麼這些外部類就可以改變這個類中的內容。
3.如果必須要返回一個引用,那麼就返回一個物件的深度拷貝,這樣儘管返回的物件內容改變了,但也儲存著原始的內容。
只提供訪問器方法(i.e. getter方法)不提供修改器方法(i.e.setter方法)
如果一定要改變這個物件的內容,那就建立一個新的不可變物件內容做相應的修改,返回修改後的物件的引用
宣告類是final的。如果一個類可以被繼承,那麼它子類就可以過載它的方法,並且修改成員變數
Java API中不可變類的例子
讓我們來回顧一下String類,用它來理解上述的幾個方面在String類實現中的體現:
所有在Stirng類中成員變數都被宣告成private,這些成員變數都在構造器中在構建物件時被初始化。
trim concat substring 都可以改變String的物件,為了保證String的不可變性,這些方法都返回的是一個改變相應內容後新的物件。
string類被宣告稱final,所以任何類都不能繼承,過載它的方法。
自己實現一個不可變類
接下來我們自己實現一個不可變類ImmutableCircle。
//ImmutableCircle.java // Point is a mutable class class Point { private int xPos, yPos; public Point(int x, int y) { xPos = x; yPos = y; } public String toString() { return "x = " + xPos + ", y = " + yPos; } int getX() { return xPos; } int getY() { return yPos; } } // ImmutableCircle is an immutable class – the state of its objects // cannot be modified once the object is created public final class ImmutableCircle { private final Point center; private final int radius; public ImmutableCircle(int x, int y, int r) { center = new Point(x, y); radius = r; } public String toString() { return "center: " + center + " and radius = " + radius; } public int getRadius() { return radius; } public Point getCenter() { // return a copy of the object to avoid // the value of center changed from code outside the class return new Point(center.getX(), center.getY()); } public static void main(String []s) { System.out.println(new ImmutableCircle(10, 10, 20)); } // other members are elided ... }
上面的程式執行之後,列印:
center: x = 10, y = 10 and radius = 20
上面的程式體現了不可變類的以下幾點:
- 這個類被宣告成final,不可以被繼承,也不可以過載它的方法
- 這個類的成員變數都是final並且是私有的
- 因為成員變數center是一個引用型別,是可變的,所以在他的getter方法中,返回的是對point物件的拷貝
設計一個不可變的類最關鍵的一點:
要注意引用型別的成員變數,如果成員變數的型別是可變的引用型別,就必須要採取必要的措施來保護這個成員變數不會被修改
不可變類不足的地方
不可變物件同樣也有不足的地方。為了保證不可變性,不可變類中的方法會建立出一定量的物件的拷貝。例如,在上面的程式碼中,每次呼叫getcenter方法都會新建並返回一個point物件的拷貝。而假如我們只需要呼叫一次,返回一個point物件,就沒必要費盡心神的去設計一個不可變類,僅僅只需要一個可變的immutablecircle類就可以了。
String類在很多應用場景中都會用到,如果我們呼叫String類中trim,concat,或者是在迴圈中呼叫substring方法,都會建立一個新的臨時String物件。同時,java也提供了Stringbuffer和Stringbuilder的可變類。他們同String一樣,但是卻可以改變這個物件的內容。所以,我們可以根據不同的場景使用String類或者Stringbuffer/Stringbuilder類。
總結,文章的最後還是那句話,要根據自己的實際需要,去設計程式碼,而不要過度設計。
譯文連結:http://www.codeceo.com/article/java-create-immutable-classes.html
英文原文:Creating Immutable Classes in Java
翻譯作者:碼農網 – 栗子蜀黍
[ 轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊。]
相關文章
- Java中如何快捷的建立不可變集合Java
- Java中String類不可變性的好處Java
- 不可變類
- Java中實現不可變MapJava
- java 中構建不可變物件Java物件
- Java中的不可變資料結構Java資料結構
- 深入理解Java中的不可變物件Java物件
- Java 10中Stream API不可變集合JavaAPI
- 【Java系列】從JVM角度解析Java核心類String的不可變特性JavaJVM
- Java 中的 String 為什麼是不可變的?Java
- Java 中建立子類物件會建立父類物件麼?Java物件
- Java中的不可變集合,我們換個方式理解!!!Java
- Java中的不可變資料結構 - Jworks.ioJava資料結構
- Java™ 教程(不可變物件)Java物件
- Python中的不可變集合Python
- 實現不可變類如何禁止子類化?
- Java 中賦值類時候修改後原類中的值改變Java賦值
- java類的建立過程Java
- Java中不可變的佇列如何實現? - XP123Java佇列
- 如何在 Python 中建立一個不可變的字典 - Adam JohnsonPython
- Java 建立類的四種方式Java
- java類變數Java變數
- 求求你,別問了,Java字串是不可變的Java字串
- 用Java編寫更好的不可變DTO的技巧 - SebJava
- 你有沒有想過: 為什麼Java中String是不可變的?Java
- Java 不可變集合 Stream流以及方法引用Java
- 為什麼Java字串是不可變物件?Java字串物件
- Java中變數之區域性變數、本類成員變數、父類成員變數的訪問方法Java變數
- 淺談Java類中的變數初始化順序Java變數
- JAVA“類”陣列的建立與呼叫Java陣列
- Java中的類(好似結構體) 物件(好似指標變數)變數 方法Java結構體物件指標變數
- Java 變數種類Java變數
- [Java基礎]String 為什麼是不可變的?Java
- java. 中 繼承Thread類建立執行緒.Java繼承thread執行緒
- 集合類再探:不可變類的好處,Collector介面詳解,使用內部迭代
- CoffeeScript攻略2.4:建立類變數變數
- Java - 24 類變數和類方法Java變數
- 不可變物件物件