java不可變對象
❶ 為什麼String對象稱為不可變的
java裡面對它的這么設定的,final修飾的。
不可變是創建後的對象不可以改變的意思。
好處:
1 不可變對象可以提高String Pool(字元串常量池)的效率和安全性。
2 對於多線程是安全的,因為在多線程同時進行的情況下,一個可變對象的值很可能被其他線程改變這樣會造成不可預期的結果,使用不可變對象就可以避免這種情況出現。
java將String設成不可變最大的原因是效率和安全。
但是當你需要向字元串插入或修改的時候,Sting不可變類型就顯得足襟見肘,這時候就需要一個可變的字元串類型:StringBuffer。
所以String和StringBuffer都存在。
❷ JAVA中為什麼說Double類是不可變類呢
對象本身,內部並沒有提供可以修改他本身的值的方法,因此這是一個不可變的類,比如他佔用了一塊內存,賦值了2,那麼你通過Double類本身的API是不能修改2這個值的,他這塊內存保存的就是2
再告訴你一個知識點,實際上,如果你用反射來修改Double的話,是可以做到修改這塊內存對應的值的
❸ 雲南java培訓學校告訴你java一些能降低競爭鎖的方法
本文介紹一下提升並發可伸縮性的一些方式:減少鎖的持有時間,降低鎖的粒度,鎖分段、避免熱點域以及採用非獨占的鎖或非阻塞鎖來代替獨占鎖。
減少鎖的持有時間
降低發生競爭可能性的一種有效方式就是盡可能縮短鎖的持有時間。例如,可以將一些與鎖無關的代碼移出同步代碼塊,尤其是那些開銷較大的操作,以及可能被阻塞的操作,例如I/O操作。
降低鎖的粒度
另一種減小鎖的持有時間的方式是降低線程請求鎖的頻率(從而減小發生競爭的可能性)。這可以通過鎖分解和鎖分段等技術來實現,在這些技術中將採用多個相互獨立的鎖來保護獨立的狀態變數,從而改變這些變數在之前由單個鎖來保護的情況。這些技術能減小鎖操作的粒度,並能實現更高的可伸縮性,然而,使用的鎖越多,那麼發生死鎖的風險也就越高。
鎖分段
在某些情況下,可以將鎖分解技術進一步擴展為對一組獨立對象上的鎖進行分解,這種情況被稱為鎖分段。例如,在ConcurrentHashMap的實現中使用了一個包含16個鎖的數組,每個鎖保護所有散列桶的1/16,其中第N個散列桶由第(Nmod16)個鎖來保護。假設散列函數具有合理的分布性,並且關鍵字能夠實現均勻分布,那麼這大約能把對於鎖的請求減少到原來的1/16。正是這項技術使得ConcurrentHashMap能夠支持多達16個並發的寫入器。(要使得擁有大量處理器的系統在高訪問量的情況下實現更高的並發性,還可以進一步增加鎖的數量,但僅當你能證明並發寫入線程的競爭足夠激烈並需要突破這個限制時,才能將鎖分段的數量超過默認的16個。)
避免熱點域
如果一個鎖保護兩個獨立變數X和Y,並且線程A想要訪問X,而線程B想要訪問Y(這類似於在ServerStatus中,一個線程調用addUser,而另一個線程調用addQuery),那麼這兩個線程不會在任何數據上發生競爭,即使它們會在同一個鎖上發生競爭。當每個操作都請求多個變數時,鎖的粒度將很難降低。這是在性能與可伸縮性之間相互制衡的另一個方面,一些常見的優化措施,例如將一些反復計算的結果緩存起來,都會引入一些「熱點域(HotField)」,而這些熱點域往往會限制可伸縮性。當實現HashMap時,你需要考慮如何在size方法中計算Map中的元素數量。最簡單的方法就是,在每次調用時都統計一次元素的數量。一種常見的優化措施是,在插入和移除元素時更新一個計數器,雖然這在put和remove等方法中略微增加了一些開銷,以確保計數器是最新的值,但這將把size方法的開銷從O(n)降低到O(l)。
代替獨占鎖
第三種降低競爭鎖的影響的技術就是放棄使用獨占鎖,從而有助於使用一種友好並發的方式來管理共享狀態。例如,使用並發容器、讀-寫鎖、不可變對象以及原子變數。昆明北大青鳥http://www.kmbdqn.cn/發現ReadWriteLock能提供比獨占鎖更高的並發性。而對於只讀的數據結構,其中包含的不變性可以完全不需要加鎖操作。
❹ java中一個類是不可變類的條件是什麼求詳細解答。
不可變類的唯一判斷條件是:
「 不可變類的實例在實例的整個生命周期中永遠保持初始化的狀態」
比如一個類裡面有個屬性是private List list,然後只提供了getList()方法,但是你還是可以通過getList().add(XXX)來修改list的內容。即是,它沒有保持「初始化」狀態,它是個可變類。
來自網路:
可變類和不可變類(Mutable and Immutable Objects)的初步定義:
可變類:當你獲得這個類的一個實例引用時,你可以改變這個實例的內容。
不可變類:當你獲得這個類的一個實例引用時,你不可以改變這個實例的內容。不可變類的實例一但創建,其內在成員變數的值就不能被修改。
如何創建一個自己的不可變類:
.所有成員都是private
.不提供對成員的改變方法,例如:setXXXX
.確保所有的方法不會被重載。手段有兩種:使用final Class(強不可變類),或者將所有類方法加上final(弱不可變類)。
.如果某一個類成員不是原始變數(primitive)或者不可變類,必須通過在成員初始化(in)或者get方法(out)時通過深度clone方法,來確保類的不可變。
❺ java函數式編程是炫技編程嗎
函數式編程(Functional Programming)是一種編程風格,它是相對於指令式編程風格而言的,常見的面向對象編程就是指令式編程風格。
指令式編程是面向計算機硬體的抽象,有變數(對應著存儲單元),賦值語句(獲取、存儲指令),表達式(內存引用和算術運算)和控制語句(跳轉語句)。
而函數式編程是面向數學的抽象,將計算描述為一種表達式求值。這里的函數實際就是數學中的函數,即自變數到因變數的映射。也就是說,一個函數的值僅決定於函數參數的值,不依賴其他狀態。
函數式編程是一種抽象程度很高的編程範式,純粹的函數式編程語言編寫的函數沒有變數,因此,任意一個函數,只要輸入是確定的,輸出就是確定的,這種純函數我們稱之為沒有副作用。而允許使用變數的程序設計語言,由於函數內部的變數狀態不確定,同樣的輸入,可能得到不同的輸出,因此,這種函數是有副作用的。
在函數式語言當中,函數作為一等公民,可以在任何地方定義,在函數內或函數外,可以作為函數的參數或返回值,可以對函數進行組合,也可以將函數賦值給變數。嚴格意義上的函數式編程意味著不適用可變的變數,賦值,循環和其他命令式控制結構進行編程。
函數式編程風格帶來的好處是:
函數式編程使用不可變對象作為變數,不會修改變數的值,而是返回一個新的值,如此這樣,更容易理清頭緒,使得單元測試和調試更加容易;
可以很自由地傳遞不可變對象,但對於可變對象來說,傳遞給其他代碼之前,需要先建造一個以防萬一的副本;
一旦不可變對象完成構造以後,就不會有線程因為並發訪問而破壞對象內部狀態,因為根本沒有線程可以改變不可變對象的狀態;
不可變對象讓哈希表鍵值更安全,所以哈希表鍵要求必須是不可變對象,否則使用可變對象,如果對象狀態發生變化,那麼在哈希表中就找不到這個對象了;
具體到編程語言,Scala(靜態語言)和Python(動態語言)都能比較的支持函數式編程風格,但是它們都不是純函數式的,也就是說它們同時支持指令式風格和函數式風格。而Java基本是指令式風格,但自從Java8引入lambda表達式以後也開始部分支持函數式風格。函數式編程最典型的是諸如map, flatMap, rece, filter等函數,它們的特點是支持某個函數作為上面這些函數的參數
❻ 為什麼Java字元串是不可變對象
從代碼層面 , 看String類的源碼你會發現 , 一個字元串對象, 其元素是一個final 修飾的byte數組 , 那麼就意味著這個字元串對象初始化之後 , 其元素(byte數組)就無法重新賦值了 , 而且String類中並沒有getValue 獲取這個數組元素的方法 , 所以就無法從數組內更改字元串對象的值 , 另外 , 字元串是放在字元串常量池的 , 既然是常量 , 自然應該是無法更改的 .
通常代碼中 對 String 的重新賦值 , 都是更改對象引用 ,就是說重新賦值之後的字元串對象 , 指向了另外一個字元串的內存地址 , 而原本字元串初始值的內存地址 , 並沒有發生改變 , 值也沒有發生改變 , 改變的是對象的引用地址 .
❼ 為什麼 java 中的 string 是不可變的
個人理解:因為string在java的編程當中比較普遍,以下的回答比較全面一些:
Java中String為什麼是不可變的
1、在Java中,String類是不可變類,一個不可變類是一個簡單的類,並且這個的實例也不能被修改,
這個類的實例創建的時候初始化所有的信息,並且這些信息不能夠被修改
2、字元串常量池
字元串常量池是方法區中一塊特殊的存儲區域,當創建一個字元串常量的時候,判斷該字元串字在符串字元串常量池中是否已經存在
如果存在,返回已經存在的字元串的引用;如果不存在,則創建一個新的字元串常量,並返回其引用
String string1 = "abcd";
String string2 = "abcd";
變數string1,string2指向常量池中的同一個字元串常量對象;如果String是可變的,給一個變數重新賦值一個引用,將會指向錯誤的值
3、緩存哈希值
在Java中字元串的哈希值會經常被使用到。例如在HashMap中,String的不可變總能保證哈希值總是相等的,並且緩存起來,不用擔心會改變,
那意味著不需要每次都計算哈希值,這樣會提高效率。在String類中有以下的代碼:
private int hash; //用來緩存哈希值
3、促進其他對象的使用
HahSet<String> set = new HashSet<String>();
set.add(new String("a"));
set.add(new String("b"));
set.add(new String("c"));
❽ java中string為什麼不可變
為什麼不可變,回答這個問題,你就要理解把它設計為不可變的好處,String作為java中最常用的一種類,提供了很多操作方法。把它設計為final有以下好處:
1:穩定性和節省內存開銷
final型會在jvm進行類載入的時候就直接進行實例化,這樣就節省以後去不斷new帶來的內存開辟成本了。實例化後固定不可變了,這樣它就是很穩定的。java程序員每天都在使用String,如果String不穩定,你想java最基本的操作還能實現嗎?
2:防篡改
final是無法被繼承的,這樣它是獨立存在的,自身封裝的很好,就不會有子類去修改它本身的方法,不會有外界來打擾它,自身結構也不會被篡改了。
3:安全性:
這和它不能被繼承這個息息相關,沒有任何類可以繼承它,就不會暴露給外部訪問它內部方法的機會,這樣它自身就比較安全了。
4:方便jvm優化
比如:String str1=「a"+"b"+1; String str2="ab1";為final的話,jvm就可以很方便的把str1的內容優化為str2,並指向同一個引用。這樣就不用再去內存中new了。
當然還有很多好處了,java設計者這樣做的根本目的就是為了保證java體系基本類的穩固和安全。
❾ java中是什麼是不可變對象和可變對象
可變對象(mutable Objects),不可變對象(Immutable ojbects)
不可變對象意味著這個對象是final的,對象中所有的公共屬性是final的。同時說明這個對象是線程安全的,這意味著他們可以在多線程中使用,而不需要使用synchronization。
可變對象和不可變對象相反,Java中大部分都是可變對象。
不可變對象有哪些
String,Integer以及其他的封裝類型都是不可變對象。
❿ 昆明Java培訓:Java如何創建不可變類
不可變類:當你獲得這個類的一個實例引用時,你不可以改變這個實例的內容。
那麼,什麼是不可變對象?一旦一個類的實例化對象被創建並初始化,那麼它就不可以被改變。
我們可以調用訪問器方法(getter),復制對象,或者傳遞對象,但是不允許任何方法改變這個對象的狀態。
包裝類(e.g.Integer或Float)和String類是不可變類的代表。
訪問器方法(accessormethod):對成員變數做出訪問的方法,e.g.getter()方法。
修改器方法(mutatormethod):對成員變數做出修改的方法,e.g.setter()方法。
定義一個不可變類如果我們要自己創建一個不可變類,需要遵守下面的規則:將成員變數(field:在一些書中也翻譯為域)聲明成final並在構造器中初始化。
對於基本類型的成員變數,用final修飾,一旦它被初始化,就不能被改變了。
而對於引用類型的成員變數,不能夠改變它的引用。
成員變數如果被聲明稱final,那麼構建對象時,必須要初始化這樣的域引用類型是可變的,我們需要採取一些措施來保證它的不可變性。
為什麼?如果我們只是聲明了一個final的可變引用類型,那麼這個引用可以去引用外部的類,或者被其他外部類引用。
在這種情況下,我們要做到:1.這些方法不會改變這些可變對象中的內容2.不要將這些引用分享到外部供其他類使用,例如,如果對成員變數的引用是可以被其他類改變的,那麼這些外部類就可以改變這個類中的內容。
3.如果必須要返回一個引用,那麼就返回一個對象的深度拷貝,這樣盡管返回的對象內容改變了,但也保存著原始的內容。
只提供訪問器方法(i.e.getter方法)不提供修改器方法(i.e.setter方法)如果一定要改變這個對象的內容,那就創建一個新的不可變對象內容做相應的修改,返回修改後的對象的引用聲明類是final的。
如果一個類可以被繼承,那麼它子類就可以重載它的方法,並且修改成員變數JavaAPI中不可變類的例子讓我們來回顧一下String類,用它來理解上述的幾個方面在String類實現中的體現:所有在Stirng類中成員變數都被聲明成private,這些成員變數都在構造器中在構建對象時被初始化。
trimconcatsubstring都可以改變String的對象,為了保證String的不可變性,這些方法都返回的是一個改變相應內容後新的對象。
string類被聲明稱final,所以任何類都不能繼承,重載它的方法。
自己實現一個不可變類接下來我們自己實現一個不可變類ImmutableCircle。
//ImmutableCircle.java//{privateintxPos,yPos;publicPoint(intx,inty){xPos=x;yPos=y;}publicStringtoString(){return"x="+xPos+",y="+yPos;}intgetX(){returnxPos;}intgetY(){returnyPos;}}//_thestateofitsobjects//{privatefinalPointcenter;privatefinalintradius;publicImmutableCircle(intx,inty,intr){center=newPoint(x,y);radius=r;}publicStringtoString(){return"center:"+center+"andradius="+radius;}publicintgetRadius(){returnradius;}publicPointgetCenter(){//returnaoftheobjecttoavoid//(center.getX(),center.getY());}publicstaticvoidmain(String[]s){System.out.println(newImmutableCircle(10,10,20));}//othermembersareelided...}上面的程序運行之後,列印:center:x=10,y=10andradius=20上面的程序體現了不可變類的以下幾點:·這個類被聲明成final,不可以被繼承,也不可以重載它的方法·這個類的成員變數都是final並且是私有的·因為成員變數center是一個引用類型,是可變的,所以在他的getter方法中,返回的是對point對象的拷貝設計一個不可變的類最關鍵的一點:要注意引用類型的成員變數,如果成員變數的類型是可變的引用類型,就必須要採取必要的措施來保護這個成員變數不會被修改不可變類不足的地方不可變對象同樣也有不足的地方。
為了保證不可變性,不可變類中的方法會創建出一定量的對象的拷貝。
例如,在上面的代碼中,每次調用getcenter方法都會新建並返回一個point對象的拷貝。
而假如我們只需要調用一次,返回一個point對象,就沒必要費盡心神的去設計一個不可變類,僅僅只需要一個可變的immutablecircle類就可以了。
String類在很多應用場景中都會用到,如果我們調用String類中trim,concat,或者是在循環中調用substring方法,都會創建一個新的臨時String對象。
同時,java也提供了Stringbuffer和Stringbuilder的可變類。
他們同String一樣,但是卻可以改變這個對象的內容。
所以,我們可以根據不同的場景使用String類或者Stringbuffer/Stringbuilder類。
總結,文章的最後還是那句話,要根據自己的實際需要,去設計代碼,而不要過度設計。