Skip to content

Commit 9face03

Browse files
committed
Java: java.lang.String
1 parent 057ab51 commit 9face03

File tree

3 files changed

+232
-0
lines changed

3 files changed

+232
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
| `-- 面试题目分类及举例.md
2929
|-- java
3030
| |-- Effective-Java.md
31+
| |-- java.lang.String.md
3132
| |-- Spring-SpringMVC-Mybatis整合.md
3233
| |-- 图解JavaCollectionFramework.md
3334
| |-- ThreadPoolExecutor源码剖析.md

java/java.lang.String.md

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
# java.lang.String
2+
3+
- 基于 Java9
4+
- Tips: 预备知识,建议掌握以后再继续向下看。[Unicode 学习笔记](../common/unicodeStandard.md)
5+
6+
---
7+
8+
<!-- TOC -->
9+
10+
- [概览](#概览)
11+
- [继承结构](#继承结构)
12+
- [Serializable](#serializable)
13+
- [CharSequence](#charsequence)
14+
- [Comparable<T>](#comparablet)
15+
- [字符集简介](#字符集简介)
16+
- [重要域成员](#重要域成员)
17+
- [重要方法](#重要方法)
18+
- [代码点及代码单元](#代码点及代码单元)
19+
- [比较](#比较)
20+
- [搜索](#搜索)
21+
- [提取子串](#提取子串)
22+
- [创建全大写/全小写副本](#创建全大写全小写副本)
23+
- [一些体会](#一些体会)
24+
- [参考](#参考)
25+
26+
<!-- /TOC -->
27+
28+
---
29+
30+
## 概览
31+
32+
`String` 类代表了字符串。所有类似于 `"abc"` 的字符串字面量都是该类的实例。
33+
34+
字符串是常量,从创建后就不可更改。需要修改的字符串可以使用 `StringBuffer`。因为 `String` 实例不可变,所以他们可以安全的共享。一些例子:
35+
36+
```java
37+
String str = "abc";
38+
// 与上面一行代码效果相同
39+
char data[] = {'a', 'b', 'c'};
40+
String str = new String(data);
41+
42+
43+
System.out.println("abc");
44+
String cde = "cde";
45+
System.out.println("abc" + cde);
46+
String c = "abc".substring(2,3);
47+
String d = cde.substring(1, 2);
48+
```
49+
50+
`String` 类也包含了一些对单个字符的操作、比较、搜索、提取子串、创建全大写/全小写副本的方法。
51+
52+
Java 语言为字符串连接操作符(+)添加了特殊支持。向左连接。
53+
54+
```java
55+
// example 1
56+
"The square root of 2 is " + Math.sqrt(2)
57+
|
58+
v
59+
"The square root of 2 is 1.4142135623730952"
60+
61+
// example 2
62+
1 + 2 + " fiddlers"
63+
|
64+
v
65+
"3 fiddlers"
66+
67+
// example 3
68+
"fiddlers " + 1 + 2
69+
|
70+
v
71+
"fiddlers 12"
72+
73+
```
74+
75+
`String` 使用 UTF-16 来编码(一个字符两个字节或四个字节)。拓展字符用 surrogate pairs 来表示,占用四个字节。(PS:该术语是编码领域的,可以参考之前写的一篇笔记: [Unicode 学习笔记](../common/unicodeStandard.md)
76+
77+
`String` 也提供了一些处理代码点(Unicode code points)和代码单元(Unicode code units)的方法(PS:这两个也是编码领域术语,可以参考:[Unicode 学习笔记](../common/unicodeStandard.md))。
78+
79+
String 连接操作符的具体实现留给 Java 编译器来决定,只要编译器能够完全遵循 Java 语言规范即可。例如 `javac` 编译器可能用 `StringBuffer``StringBuilder``java.lang.invoke.StringCOncatFactory` 来实现。
80+
81+
## 继承结构
82+
83+
![](../res/java.lang.string-class.png)
84+
85+
### Serializable
86+
87+
类通过实现 `java.io.Serializable` 接口来启用序列化能力。未实现该接口的类其状态将不会被序列化(抛出 `NotSerializableException` 异常)。该接口没有任何域或方法,只是表示可序列化的语义。
88+
89+
```java
90+
public static void serializableTest() throws IOException, ClassNotFoundException {
91+
String outputfile = "/Users/chen/Desktop/serializable";
92+
ST instance = new ST();
93+
94+
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(outputfile));
95+
outputStream.writeObject(instance);
96+
outputStream.close();
97+
98+
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(outputfile));
99+
ST newInstance = (ST) inputStream.readObject();
100+
inputStream.close();
101+
102+
System.out.println(newInstance);
103+
System.out.println(instance.equals(newInstance)); // true
104+
System.out.println(instance == newInstance); //false
105+
}
106+
107+
static class ST implements Serializable{
108+
public int publicField = 1;
109+
protected int protectedField = 1;
110+
int defaultField = 1;
111+
private int privateField = 1;
112+
113+
@Override
114+
public boolean equals(Object o) {
115+
if (this == o) {
116+
return true;
117+
}
118+
if (o == null || getClass() != o.getClass()) {
119+
return false;
120+
}
121+
ST st = (ST) o;
122+
return publicField == st.publicField &&
123+
protectedField == st.protectedField &&
124+
defaultField == st.defaultField &&
125+
privateField == st.privateField;
126+
}
127+
128+
@Override
129+
public int hashCode() {
130+
return Objects.hash(publicField, protectedField, defaultField, privateField);
131+
}
132+
133+
@Override
134+
public String toString() {
135+
return "ST{" +
136+
"publicField=" + publicField +
137+
", protectedField=" + protectedField +
138+
", defaultField=" + defaultField +
139+
", privateField=" + privateField +
140+
'}';
141+
}
142+
}
143+
```
144+
145+
序列化的对象中引用的所有对象都必须实现了该接口,否则也会抛出 `NotSerializableException` 异常。
146+
147+
### CharSequence
148+
149+
一个 `CharSequence` 是一个只读的 `char` 序列。该接口为不同的实现提供了统一的只读访问。
150+
151+
该接口并没有重新定义 `equals() & hashCode()` 方法,直接比较两个实现类的实例结果是未定义的。所以将 `CharSequence` 的实例作为 `set` 的元素或 `map``key` 是不合适的。
152+
153+
主要的实现类:`CharBuffer, Segment, String, StringBuffer, StringBuilder`
154+
155+
`String` 中也实现了与 `CharSequence` 实例进行比较、拼接等操作的函数。
156+
157+
### Comparable<T>
158+
159+
主要用于集合中元素排序,两个元素直接比较。
160+
161+
## 字符集简介
162+
163+
`String` 类中用到了两种字符集 `Latin1 & UTF-16`. `Latin1` 拓展了 `ASCII` 编码,但是也是用一个字节来表示,`UTF-16` 使用两个或四个字节表示一个字符。简要介绍请看:[Unicode 学习笔记](../common/unicodeStandard.md)
164+
165+
```java
166+
/**
167+
在构造一个 String 对象时,String 会尝试对传入的参数进行压缩。比如
168+
169+
String latin1 = new String("latin1".toCharArray());
170+
String utf16 = new String("使用 UTF-16 字符集".toCharArray());
171+
172+
入参是 char[],java 中 char 是两个字节,byte 是一个字节,压缩后 latin1 的 value 字段是 6 个 byte,utf16 无法进行压缩,所以依旧是 26 个 byte。
173+
174+
下面是 java.lang.StringUTF16 中进行压缩的函数。
175+
*/
176+
// compressedCopy char[] -> byte[]
177+
@HotSpotIntrinsicCandidate
178+
public static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) {
179+
for (int i = 0; i < len; i++) {
180+
char c = src[srcOff];
181+
if (c > 0xFF) { // 超出了 LATIN1 所能表示的范围,直接返回不再压缩
182+
len = 0;
183+
break;
184+
}
185+
dst[dstOff] = (byte)c;
186+
srcOff++;
187+
dstOff++;
188+
}
189+
return len;
190+
}
191+
```
192+
193+
## 重要域成员
194+
195+
1. `private final byte[] value;`
196+
- 用来存储字符串的字节序列。
197+
1. `private final byte coder;`
198+
- 用来暗示 `value` 中的字节数组的编码方式。有 `LATIN1 & UTF16` 可选。
199+
- `static final byte LATIN1 = 0;`
200+
- `static final byte UTF16 = 1;`
201+
1. `private int hash;`
202+
- 缓存字符串哈希值。默认是 0. 在 首次调用 `hashCode()` 方法时计算并缓存。
203+
1. `static final boolean COMPACT_STRINGS;`
204+
- 用来决定 `value` 是否进行压缩,默认是 true(压缩)。如果是 false 的话那么总是使用 UTF16 来编码字符串的字节流。在 `String` 类中,该域使用静态初始化块进行初始化。
205+
206+
## 重要方法
207+
208+
- TIPS:本来计划中有这部分的内容,但是读过源码理解了字符集的概念和 `String` 的处理方式以后感觉这部分就不需要再写了,有兴趣可以自己看。
209+
210+
### 代码点及代码单元
211+
212+
### 比较
213+
214+
### 搜索
215+
216+
### 提取子串
217+
218+
### 创建全大写/全小写副本
219+
220+
## 一些体会
221+
222+
理解 `String` 类最重要的不是会用 `String` 的 API,而是对字符集本身的理解,字符集是什么,它解决了什么问题,字符是怎么编码的等等,只有很好的理解了字符集才能很好的理解 `String` 的行为。
223+
224+
## 参考
225+
226+
1. [java.lang.String](https://docs.oracle.com/javase/9/docs/api/java/lang/String.html)
227+
1. [15.18.1. String Concatenation Operator +](https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.18.1)
228+
1. [Serializable](https://docs.oracle.com/javase/9/docs/api/java/io/Serializable.html)
229+
1. [JAVA 对象序列化(一)——Serializable](http://www.cnblogs.com/chenfei0801/archive/2013/04/05/3001149.html)
230+
1. [CharSequence](https://docs.oracle.com/javase/9/docs/api/java/lang/CharSequence.html)
231+
1. [ISO/IEC 8859-1](https://en.wikipedia.org/wiki/ISO/IEC_8859-1)

res/java.lang.string-class.png

38.2 KB
Loading

0 commit comments

Comments
 (0)