forked from hollischuang/toBeTopJavaer
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
hollis.zhl
committed
Jun 20, 2021
1 parent
cee1839
commit 215fa0e
Showing
23 changed files
with
349 additions
and
376 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,3 +57,4 @@ fabric.properties | |
# Editor-based Rest Client | ||
.idea/httpRequests | ||
|
||
.DS_Store |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,109 @@ | ||
String在Java中特别常用,而且我们经常要在代码中对字符串进行赋值和改变他的值,但是,为什么我们说字符串是不可变的呢? | ||
|
||
* * * | ||
首先,我们需要知道什么是不可变对象? | ||
|
||
## 定义一个字符串 | ||
不可变对象是在完全创建后其内部状态保持不变的对象。这意味着,一旦对象被赋值给变量,我们既不能更新引用,也不能通过任何方式改变内部状态。 | ||
|
||
String s = "abcd"; | ||
|
||
可是有人会有疑惑,String为什么不可变,我的代码中经常改变String的值啊,如下: | ||
|
||
![String-Immutability-1][1] | ||
``` | ||
String s = "abcd"; | ||
s = s.concat("ef"); | ||
|
||
`s`中保存了string对象的引用。下面的箭头可以理解为“存储他的引用”。 | ||
``` | ||
|
||
## 使用变量来赋值变量 | ||
|
||
String s2 = s; | ||
|
||
这样,操作,不就将原本的"abcd"的字符串改变成"abcdef"了么? | ||
|
||
![String-Immutability-2][2] | ||
但是,虽然字符串内容看上去从"abcd"变成了"abcdef",但是实际上,我们得到的已经是一个新的字符串了。 | ||
|
||
s2保存了相同的引用值,因为他们代表同一个对象。 | ||
![][1] | ||
|
||
## 字符串连接 | ||
如上图,在堆中重新创建了一个"abcdef"字符串,和"abcd"并不是同一个对象。 | ||
|
||
s = s.concat("ef"); | ||
|
||
所以,一旦一个string对象在内存(堆)中被创建出来,他就无法被修改。而且,String类的所有方法都没有改变字符串本身的值,都是返回了一个新的对象。 | ||
|
||
![string-immutability][3] | ||
如果我们想要一个可秀改的字符串,可以选择StringBuffer 或者 StringBuilder这两个代替String。 | ||
|
||
`s`中保存的是一个重新创建出来的string对象的引用。 | ||
### 为什么String要设计成不可变 | ||
|
||
## 总结 | ||
在知道了"String是不可变"的之后,大家是不是一定都很疑惑:为什么要把String设计成不可变的呢?有什么好处呢? | ||
|
||
一旦一个string对象在内存(堆)中被创建出来,他就无法被修改。特别要注意的是,String类的所有方法都没有改变字符串本身的值,都是返回了一个新的对象。 | ||
这个问题,困扰过很多人,甚至有人直接问过Java的创始人James Gosling。 | ||
|
||
如果你需要一个可修改的字符串,应该使用StringBuffer 或者 StringBuilder。否则会有大量时间浪费在垃圾回收上,因为每次试图修改都有新的string对象被创建出来。 | ||
在一次采访中James Gosling被问到什么时候应该使用不可变变量,他给出的回答是: | ||
|
||
[1]: http://www.programcreek.com/wp-content/uploads/2009/02/String-Immutability-1.jpeg | ||
[2]: http://www.programcreek.com/wp-content/uploads/2009/02/String-Immutability-2.jpeg | ||
[3]: http://www.programcreek.com/wp-content/uploads/2009/02/string-immutability-650x279.jpeg | ||
> I would use an immutable whenever I can. | ||
|
||
那么,他给出这个答案背后的原因是什么呢?是基于哪些思考的呢? | ||
|
||
其实,主要是从缓存、安全性、线程安全和性能等角度触发的。 | ||
|
||
Q:缓存、安全性、线程安全和性能?这有都是啥 | ||
A:你别急,听我一个一个给你讲就好了。 | ||
|
||
#### 缓存 | ||
|
||
字符串是使用最广泛的数据结构。大量的字符串的创建是非常耗费资源的,所以,Java提供了对字符串的缓存功能,可以大大的节省堆空间。 | ||
|
||
JVM中专门开辟了一部分空间来存储Java字符串,那就是字符串池。 | ||
|
||
通过字符串池,两个内容相同的字符串变量,可以从池中指向同一个字符串对象,从而节省了关键的内存资源。 | ||
|
||
``` | ||
String s = "abcd"; | ||
String s2 = s; | ||
``` | ||
|
||
|
||
对于这个例子,s和s2都表示"abcd",所以他们会指向字符串池中的同一个字符串对象: | ||
|
||
![][2] | ||
|
||
但是,之所以可以这么做,主要是因为字符串的不变性。试想一下,如果字符串是可变的,我们一旦修改了s的内容,那必然导致s2的内容也被动的改变了,这显然不是我们想看到的。 | ||
|
||
#### 安全性 | ||
|
||
字符串在Java应用程序中广泛用于存储敏感信息,如用户名、密码、连接url、网络连接等。JVM类加载器在加载类的时也广泛地使用它。 | ||
|
||
因此,保护String类对于提升整个应用程序的安全性至关重要。 | ||
|
||
当我们在程序中传递一个字符串的时候,如果这个字符串的内容是不可变的,那么我们就可以相信这个字符串中的内容。 | ||
|
||
但是,如果是可变的,那么这个字符串内容就可能随时都被修改。那么这个字符串内容就完全可信了。这样整个系统就没有安全性可言了。 | ||
|
||
#### 线程安全 | ||
|
||
不可变会自动使字符串成为线程安全的,因为当从多个线程访问它们时,它们不会被更改。 | ||
|
||
因此,一般来说,不可变对象可以在同时运行的多个线程之间共享。它们也是线程安全的,因为如果线程更改了值,那么将在字符串池中创建一个新的字符串,而不是修改相同的值。因此,字符串对于多线程来说是安全的。 | ||
|
||
#### hashcode缓存 | ||
|
||
由于字符串对象被广泛地用作数据结构,它们也被广泛地用于哈希实现,如HashMap、HashTable、HashSet等。在对这些散列实现进行操作时,经常调用hashCode()方法。 | ||
|
||
不可变性保证了字符串的值不会改变。因此,hashCode()方法在String类中被重写,以方便缓存,这样在第一次hashCode()调用期间计算和缓存散列,并从那时起返回相同的值。 | ||
|
||
在String类中,有以下代码: | ||
|
||
``` | ||
private int hash;//this is used to cache hash code. | ||
``` | ||
|
||
|
||
#### 性能 | ||
|
||
前面提到了的字符串池、hashcode缓存等,都是提升性能的提现。 | ||
|
||
因为字符串不可变,所以可以用字符串池缓存,可以大大节省堆内存。而且还可以提前对hashcode进行缓存,更加高效 | ||
|
||
由于字符串是应用最广泛的数据结构,提高字符串的性能对提高整个应用程序的总体性能有相当大的影响。 | ||
|
||
### 总结 | ||
|
||
通过本文,我们可以得出这样的结论:字符串是不可变的,因此它们的引用可以被视为普通变量,可以在方法之间和线程之间传递它们,而不必担心它所指向的实际字符串对象是否会改变。 | ||
|
||
我们还了解了促使Java语言设计人员将该类设置为不可变类的其他原因。主要考虑的是缓存、安全性、线程安全和性能等方面 | ||
|
||
[1]: https://www.hollischuang.com/wp-content/uploads/2021/03/16163108328434.jpg | ||
[2]: https://www.hollischuang.com/wp-content/uploads/2021/03/16163114985563.jpg |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.