Skip to content

Commit 215fa0e

Browse files
author
hollis.zhl
committed
知识点更新
1 parent cee1839 commit 215fa0e

23 files changed

Lines changed: 349 additions & 376 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,4 @@ fabric.properties
5757
# Editor-based Rest Client
5858
.idea/httpRequests
5959

60+
.DS_Store

docs/basics/java-basic/constructor.md

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 92 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,109 @@
1+
String在Java中特别常用,而且我们经常要在代码中对字符串进行赋值和改变他的值,但是,为什么我们说字符串是不可变的呢?
12

2-
* * *
3+
首先,我们需要知道什么是不可变对象?
34

4-
## 定义一个字符串
5+
不可变对象是在完全创建后其内部状态保持不变的对象。这意味着,一旦对象被赋值给变量,我们既不能更新引用,也不能通过任何方式改变内部状态。
56

6-
String s = "abcd";
7-
7+
可是有人会有疑惑,String为什么不可变,我的代码中经常改变String的值啊,如下:
88

9-
![String-Immutability-1][1]
9+
```
10+
String s = "abcd";
11+
s = s.concat("ef");
1012
11-
`s`中保存了string对象的引用。下面的箭头可以理解为“存储他的引用”。
13+
```
1214

13-
## 使用变量来赋值变量
1415

15-
String s2 = s;
16-
16+
这样,操作,不就将原本的"abcd"的字符串改变成"abcdef"了么?
1717

18-
![String-Immutability-2][2]
18+
但是,虽然字符串内容看上去从"abcd"变成了"abcdef",但是实际上,我们得到的已经是一个新的字符串了。
1919

20-
s2保存了相同的引用值,因为他们代表同一个对象。
20+
![][1]
2121

22-
## 字符串连接
22+
如上图,在堆中重新创建了一个"abcdef"字符串,和"abcd"并不是同一个对象。
2323

24-
s = s.concat("ef");
25-
24+
所以,一旦一个string对象在内存(堆)中被创建出来,他就无法被修改。而且,String类的所有方法都没有改变字符串本身的值,都是返回了一个新的对象。
2625

27-
![string-immutability][3]
26+
如果我们想要一个可秀改的字符串,可以选择StringBuffer 或者 StringBuilder这两个代替String。
2827

29-
`s`中保存的是一个重新创建出来的string对象的引用。
28+
### 为什么String要设计成不可变
3029

31-
## 总结
30+
在知道了"String是不可变"的之后,大家是不是一定都很疑惑:为什么要把String设计成不可变的呢?有什么好处呢?
3231

33-
一旦一个string对象在内存(堆)中被创建出来,他就无法被修改。特别要注意的是,String类的所有方法都没有改变字符串本身的值,都是返回了一个新的对象
32+
这个问题,困扰过很多人,甚至有人直接问过Java的创始人James Gosling
3433

35-
如果你需要一个可修改的字符串,应该使用StringBuffer 或者 StringBuilder。否则会有大量时间浪费在垃圾回收上,因为每次试图修改都有新的string对象被创建出来。
34+
在一次采访中James Gosling被问到什么时候应该使用不可变变量,他给出的回答是:
3635

37-
[1]: http://www.programcreek.com/wp-content/uploads/2009/02/String-Immutability-1.jpeg
38-
[2]: http://www.programcreek.com/wp-content/uploads/2009/02/String-Immutability-2.jpeg
39-
[3]: http://www.programcreek.com/wp-content/uploads/2009/02/string-immutability-650x279.jpeg
36+
> I would use an immutable whenever I can.
37+
38+
那么,他给出这个答案背后的原因是什么呢?是基于哪些思考的呢?
39+
40+
其实,主要是从缓存、安全性、线程安全和性能等角度触发的。
41+
42+
Q:缓存、安全性、线程安全和性能?这有都是啥
43+
A:你别急,听我一个一个给你讲就好了。
44+
45+
#### 缓存
46+
47+
字符串是使用最广泛的数据结构。大量的字符串的创建是非常耗费资源的,所以,Java提供了对字符串的缓存功能,可以大大的节省堆空间。
48+
49+
JVM中专门开辟了一部分空间来存储Java字符串,那就是字符串池。
50+
51+
通过字符串池,两个内容相同的字符串变量,可以从池中指向同一个字符串对象,从而节省了关键的内存资源。
52+
53+
```
54+
String s = "abcd";
55+
String s2 = s;
56+
```
57+
58+
59+
对于这个例子,s和s2都表示"abcd",所以他们会指向字符串池中的同一个字符串对象:
60+
61+
![][2]
62+
63+
但是,之所以可以这么做,主要是因为字符串的不变性。试想一下,如果字符串是可变的,我们一旦修改了s的内容,那必然导致s2的内容也被动的改变了,这显然不是我们想看到的。
64+
65+
#### 安全性
66+
67+
字符串在Java应用程序中广泛用于存储敏感信息,如用户名、密码、连接url、网络连接等。JVM类加载器在加载类的时也广泛地使用它。
68+
69+
因此,保护String类对于提升整个应用程序的安全性至关重要。
70+
71+
当我们在程序中传递一个字符串的时候,如果这个字符串的内容是不可变的,那么我们就可以相信这个字符串中的内容。
72+
73+
但是,如果是可变的,那么这个字符串内容就可能随时都被修改。那么这个字符串内容就完全可信了。这样整个系统就没有安全性可言了。
74+
75+
#### 线程安全
76+
77+
不可变会自动使字符串成为线程安全的,因为当从多个线程访问它们时,它们不会被更改。
78+
79+
因此,一般来说,不可变对象可以在同时运行的多个线程之间共享。它们也是线程安全的,因为如果线程更改了值,那么将在字符串池中创建一个新的字符串,而不是修改相同的值。因此,字符串对于多线程来说是安全的。
80+
81+
#### hashcode缓存
82+
83+
由于字符串对象被广泛地用作数据结构,它们也被广泛地用于哈希实现,如HashMap、HashTable、HashSet等。在对这些散列实现进行操作时,经常调用hashCode()方法。
84+
85+
不可变性保证了字符串的值不会改变。因此,hashCode()方法在String类中被重写,以方便缓存,这样在第一次hashCode()调用期间计算和缓存散列,并从那时起返回相同的值。
86+
87+
在String类中,有以下代码:
88+
89+
```
90+
private int hash;//this is used to cache hash code.
91+
```
92+
93+
94+
#### 性能
95+
96+
前面提到了的字符串池、hashcode缓存等,都是提升性能的提现。
97+
98+
因为字符串不可变,所以可以用字符串池缓存,可以大大节省堆内存。而且还可以提前对hashcode进行缓存,更加高效
99+
100+
由于字符串是应用最广泛的数据结构,提高字符串的性能对提高整个应用程序的总体性能有相当大的影响。
101+
102+
### 总结
103+
104+
通过本文,我们可以得出这样的结论:字符串是不可变的,因此它们的引用可以被视为普通变量,可以在方法之间和线程之间传递它们,而不必担心它所指向的实际字符串对象是否会改变。
105+
106+
我们还了解了促使Java语言设计人员将该类设置为不可变类的其他原因。主要考虑的是缓存、安全性、线程安全和性能等方面
107+
108+
[1]: https://www.hollischuang.com/wp-content/uploads/2021/03/16163108328434.jpg
109+
[2]: https://www.hollischuang.com/wp-content/uploads/2021/03/16163114985563.jpg

docs/basics/java-basic/inheritance-composition.md

Lines changed: 0 additions & 67 deletions
This file was deleted.

docs/basics/java-basic/replace-in-string.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,5 @@ replaceAll和replaceFirst的区别主要是替换的内容不同,replaceAll是
2424

2525
//使用replaceFirst将第一个数字替换成H
2626
System.out.println(string.replaceFirst("\\d","H"));//abcH23adb23456aa
27-
//使用replaceFirst将所有数字替换成H
27+
//使用replaceAll将所有数字替换成H
2828
System.out.println(string.replaceAll("\\d","H"));//abcHHHadbHHHHHaa

docs/basics/java-basic/scope.md

Lines changed: 0 additions & 7 deletions
This file was deleted.

docs/basics/java-basic/string-append.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
Java中,想要拼接字符串,最简单的方式就是通过"+"连接两个字符串。
2+
13
有人把Java中使用+拼接字符串的功能理解为运算符重载。其实并不是,Java是不支持运算符重载的。这其实只是Java提供的一个语法糖。
24

35
>运算符重载:在计算机程序设计中,运算符重载(英语:operator overloading)是多态的一种。运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。

docs/basics/java-basic/substring.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
String是Java中一个比较基础的类,每一个开发人员都会经常接触到。而且,String也是面试中经常会考的知识点。String有很多方法,有些方法比较常用,有些方法不太常用。今天要介绍的substring就是一个比较常用的方法,而且围绕substring也有很多面试题。
1+
String是Java中一个比较基础的类,每一个开发人员都会经常接触到。而且,String也是面试中经常会考的知识点。
2+
3+
String有很多方法,有些方法比较常用,有些方法不太常用。今天要介绍的substring就是一个比较常用的方法,而且围绕substring也有很多面试题。
24

35
`substring(int beginIndex, int endIndex)`方法在不同版本的JDK中的实现是不同的。了解他们的区别可以帮助你更好的使用他。为简单起见,后文中用`substring()`代表`substring(int beginIndex, int endIndex)`方法。
46

docs/basics/java-basic/switch-string.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
Java 7中,switch的参数可以是String类型了,这对我们来说是一个很方便的改进。到目前为止switch支持这样几种数据类型:`byte` `short` `int` `char` `String` 。但是,作为一个程序员我们不仅要知道他有多么好用,还要知道它是如何实现的,switch对整型的支持是怎么实现的呢?对字符型是怎么实现的呢?String类型呢?有一点Java开发经验的人这个时候都会猜测switch对String的支持是使用equals()方法和hashcode()方法。那么到底是不是这两个方法呢?接下来我们就看一下,switch到底是如何实现的。
22

3-
<!--more-->
4-
53
### 一、switch对整型支持的实现
64

75
下面是一段很简单的Java代码,定义一个int型变量a,然后使用switch语句进行判断。执行这段代码输出内容为5,那么我们将下面这段代码反编译,看看他到底是怎么实现的。

docs/basics/java-basic/variable.md

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)