Skip to content

Commit 02db2ac

Browse files
committed
Add images/1.png
Add images/2.png Add section1.md Add section10.md Add section11.md Add section2.md Add section3.md Add section4.md Add section5.md Add section6.md Add section7.md Add section8.md Add section9.md
1 parent af497d9 commit 02db2ac

13 files changed

+1286
-0
lines changed

images/1.png

29.6 KB
Loading

images/2.png

49.7 KB
Loading

section1.md

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# 数据类型
2+
3+
## 基本类型
4+
- byte/8
5+
- char/16
6+
- short/16
7+
- int/32
8+
- float/32
9+
- long/64
10+
- double/64
11+
- boolean/~
12+
13+
boolean 只有两个值:true、false,可以使用 1 bit 来存储,但是具体⼤小没有明确规定。JVM 会在编
14+
译时期将 boolean 类型的数据转换为 int,使用 1 来表示 true,0 表示 false。JVM ⽀持 boolean 数组,
15+
但是是通过读写 byte 数组来实现的。
16+
17+
## 包装类型
18+
基本类型都有对应的包装类型,基本类型与其对应的包装类型之间的赋值使⽤⾃动装箱与拆箱完成。
19+
20+
```java
21+
Integer x = 2; // 装箱 调⽤用了 Integer.valueOf(2)
22+
int y = x; // 拆箱 调⽤用了 X.intValue()
23+
```
24+
## 缓存池
25+
26+
new Integer(123) 与 Integer.valueOf(123) 的区别在于:
27+
28+
- new Integer(123) 每次都会新建⼀一个对象;
29+
- Integer.valueOf(123) 会使用缓存池中的对象,多次调⽤用会取得同⼀一个对象的引用。
30+
31+
```java
32+
Integer x = new Integer(123);
33+
Integer y = new Integer(123);
34+
System.out.println(x == y); // false
35+
Integer z = Integer.valueOf(123);
36+
Integer k = Integer.valueOf(123);
37+
System.out.println(z == k); // true
38+
```
39+
valueOf() 方法的实现比较简单,就是先判断值是否在缓存池中,如果在的话就直接返回缓存池的内容。
40+
41+
```java
42+
public static Integer valueOf(int i) {
43+
if (i >= IntegerCache.low && i <= IntegerCache.high)
44+
return IntegerCache.cache[i + (-IntegerCache.low)];
45+
return new Integer(i);
46+
}
47+
```
48+
49+
在 java 8 中,Integer 缓存池的⼤⼩默认为 -128~127。
50+
51+
```java
52+
static final int low = -128;
53+
static final int high;
54+
static final Integer cache[];
55+
56+
static {
57+
// high value may be configured by property
58+
int h = 127;
59+
String integerCacheHighPropValue =
60+
61+
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
62+
if (integerCacheHighPropValue != null) {
63+
try {
64+
int i = parseInt(integerCacheHighPropValue);
65+
i = Math.max(i, 127);
66+
// Maximum array size is Integer.MAX_VALUE
67+
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
68+
} catch( NumberFormatException nfe) {
69+
// If the property cannot be parsed into an int, ignore it.
70+
}
71+
}
72+
high = h;
73+
74+
cache = new Integer[(high - low) + 1];
75+
int j = low;
76+
for(int k = 0; k < cache.length; k++){
77+
cache[k] = new Integer(j++);
78+
79+
// range [-128, 127] must be interned (JLS7 5.1.7)
80+
assert IntegerCache.high >= 127;
81+
}
82+
```
83+
84+
编译器会在自动装箱过程调⽤用 valueOf() ⽅法,因此多个值相同且值在缓存池范围内的 Integer 实例使用
85+
自动装箱来创建,那么就会引⽤相同的对象。
86+
87+
```java
88+
Integer m = 123;
89+
Integer n = 123;
90+
System.out.println(m == n); // true
91+
```
92+
93+
基本类型对应的缓冲池如下:
94+
- boolean values true and false
95+
- all byte values
96+
- short values between -128 and 127
97+
- int values between -128 and 127
98+
- char in the range \u0000 to \u007F
99+
100+
在使用这些基本类型对应的包装类型时,如果该数值范围在缓冲池范围内,就可以直接使用缓冲池中的对象。
101+
102+
在 jdk 1.8 所有的数值类缓冲池中,Integer 的缓冲池 IntegerCache 很特殊,这个缓冲池的下界是 -128,上界默认是 127,但是这个上界是可调的,在启动 jvm 的时候,通过 -XX:AutoBoxCacheMax=<size> 来指定这个缓冲池的⼤大⼩小,该选项在 JVM 初始化的时候会设定⼀个名为java.lang.IntegerCache.high 系统属性,然后 IntegerCache 初始化的时候就会读取该系统属性来决定上界。
103+
104+

section10.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# 注解
2+
3+
Java 注解是附加在代码中的⼀些元信息,⽤于⼀些⼯具在编译、运⾏时进⾏解析和使⽤,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作⽤。
4+
5+
[注解Annotation实现原理与自定义注解例子](https://www.cnblogs.com/acm-bingzi/p/javaAnnotation.html)

section11.md

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# 特性
2+
3+
Java 各版本的新特性
4+
public class Box<T> {
5+
// T stands for "Type"
6+
private T t;
7+
public void set(T t) { this.t = t; }
8+
public T get() { return t; }
9+
}
10+
### New highlights in Java SE 8
11+
1. Lambda Expressions
12+
2. Pipelines and Streams
13+
3. Date and Time API
14+
4. Default Methods
15+
5. Type Annotations
16+
6. Nashhorn JavaScript Engine
17+
7. Concurrent Accumulators
18+
8. Parallel operations
19+
9. PermGen Error Removed
20+
### New highlights in Java SE 7
21+
1. Strings in Switch Statement
22+
2. Type Inference for Generic Instance Creation
23+
3. Multiple Exception Handling
24+
4. Support for Dynamic Languages
25+
5. Try with Resources
26+
6. Java nio Package
27+
7. Binary Literals, Underscore in literals
28+
8. Diamond Syntax
29+
30+
## Java 与 C++ 的区别
31+
- Java 是纯粹的⾯向对象语⾔,所有的对象都继承⾃ java.lang.Object,C++ 为了兼容 C 即⽀持⾯向对象也⽀持⾯向过程。
32+
- Java 通过虚拟机从⽽实现跨平台特性,但是 C++ 依赖于特定的平台。
33+
- Java 没有指针,它的引⽤可以理解为安全指针,⽽ C++ 具有和 C ⼀样的指针。
34+
- Java ⽀持⾃动垃圾回收,⽽ C++ 需要⼿动回收。
35+
- Java 不⽀持多重继承,只能通过实现多个接⼝来达到相同⽬的,⽽ C++ ⽀持多重继承。
36+
- Java 不⽀持操作符重载,虽然可以对两个 String 对象执⾏加法运算,但是这是语⾔内置⽀持的操作,不属于操作符重载,⽽ C++ 可以。
37+
- Java 的 goto 是保留字,但是不可⽤,C++ 可以使⽤ goto。
38+
39+
## JRE or JDK
40+
- JRE:Java Runtime Environment,Java 运⾏环境的简称,为 Java 的运⾏提供了所需的环境。它是⼀个 JVM 程序,主要包括了 JVM 的标准实现和⼀些 Java 基本类库。
41+
- JDK:Java Development Kit,Java 开发⼯具包,提供了 Java 的开发及运⾏环境。JDK 是 Java 开发的核⼼,集成了 JRE 以及⼀些其它的⼯具,⽐如编译 Java 源码的编译器 javac 等。
42+
43+

section2.md

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# String
2+
3+
## 概览
4+
5+
String 被声明为 final,因此它不不可被继承。(Integer 等包装类也不不能被继承)
6+
在 Java 8 中,String 内部使⽤用 char 数组存储数据。
7+
8+
```java
9+
public final class String
10+
implements java.io.Serializable, Comparable<String>, CharSequence {
11+
/** The value is used for character storage. */
12+
private final char value[];
13+
}
14+
```
15+
16+
在 Java 9 之后,String 类的实现改⽤用 byte 数组存储字符串串,同时使⽤用 coder 来标识使⽤用了了哪种编
17+
码。
18+
19+
```java
20+
public final class String
21+
implements java.io.Serializable, Comparable<String>, CharSequence {
22+
/** The value is used for character storage. */
23+
private final byte[] value;
24+
25+
/** The identifier of the encoding used to encode the bytes in {@code
26+
value}. */
27+
private final byte coder;
28+
}
29+
```
30+
31+
在 Java 9 之后,String 类的实现改⽤用 byte 数组存储字符串串,同时使⽤用 coder 来标识使⽤用了了哪种编
32+
码。
33+
value 数组被声明为 final,这意味着 value 数组初始化之后就不不能再引⽤用其它数组。并且 String 内部没
34+
有改变 value 数组的⽅方法,因此可以保证 String 不不可变。
35+
36+
## 不可变的好处
37+
38+
### 1. 可以缓存 hash 值
39+
40+
因为 String 的 hash 值经常被使⽤用,例例如 String ⽤用做 HashMap 的 key。不不可变的特性可以使得 hash
41+
值也不不可变,因此只需要进⾏行行⼀一次计算。
42+
43+
### 2. String Pool 的需要
44+
45+
如果⼀一个 String 对象已经被创建过了了,那么就会从 String Pool 中取得引⽤用。只有 String 是不不可变的,
46+
才可能使⽤用 String Pool。
47+
48+
![](images/1.png)
49+
50+
### 3. 安全性
51+
52+
String 经常作为参数,String 不不可变性可以保证参数不不可变。例例如在作为⽹网络连接参数的情况下如果
53+
String 是可变的,那么在⽹网络连接过程中,String 被改变,改变 String 的那⼀一⽅方以为现在连接的是其它
54+
主机,⽽而实际情况却不不⼀一定是。
55+
56+
### 4. 线程安全
57+
58+
String 不不可变性天⽣生具备线程安全,可以在多个线程中安全地使⽤用。
59+
Program Creek : Why String is immutable in Java?
60+
61+
## String, StringBuffer and StringBuilder
62+
63+
### 1. 可变性
64+
String 不不可变
65+
StringBuffer 和 StringBuilder 可变
66+
### 2. 线程安全
67+
String 不不可变,因此是线程安全的
68+
StringBuilder 不不是线程安全的
69+
StringBuffer 是线程安全的,内部使⽤用 synchronized 进⾏行行同步
70+
71+
## String Pool
72+
73+
字符串串常量量池(String Pool)保存着所有字符串串字⾯面量量(literal strings),这些字⾯面量量在编译时期就确
74+
定。不不仅如此,还可以使⽤用 String 的 intern() ⽅方法在运⾏行行过程将字符串串添加到 String Pool 中。
75+
当⼀一个字符串串调⽤用 intern() ⽅方法时,如果 String Pool 中已经存在⼀一个字符串串和该字符串串值相等(使⽤用
76+
equals() ⽅方法进⾏行行确定),那么就会返回 String Pool 中字符串串的引⽤用;否则,就会在 String Pool 中添
77+
加⼀一个新的字符串串,并返回这个新字符串串的引⽤用。
78+
下⾯面示例例中,s1 和 s2 采⽤用 new String() 的⽅方式新建了了两个不不同字符串串,⽽而 s3 和 s4 是通过 s1.intern()
79+
和 s2.intern() ⽅方法取得同⼀一个字符串串引⽤用。intern() ⾸首先把 "aaa" 放到 String Pool 中,然后返回这个字
80+
符串串引⽤用,因此 s3 和 s4 引⽤用的是同⼀一个字符串串
81+
82+
```java
83+
String s1 = new String("aaa");
84+
String s2 = new String("aaa");
85+
System.out.println(s1 == s2); // false
86+
String s3 = s1.intern();
87+
String s4 = s2.intern();
88+
System.out.println(s3 == s4); // true
89+
```
90+
91+
如果是采⽤用 "bbb" 这种字⾯面量量的形式创建字符串串,会⾃自动地将字符串串放⼊入 String Pool 中。
92+
93+
```java
94+
String s5 = "bbb";
95+
String s6 = "bbb";
96+
System.out.println(s5 == s6); // true
97+
```
98+
99+
在 Java 7 之前,String Pool 被放在运⾏行行时常量量池中,它属于永久代。⽽而在 Java 7,String Pool 被移到
100+
堆中。这是因为永久代的空间有限,在⼤大量量使⽤用字符串串的场景下会导致 OutOfMemoryError 错误。
101+
102+
## new String("abc")
103+
104+
使⽤用这种⽅方式⼀一共会创建两个字符串串对象(前提是 String Pool 中还没有 "abc" 字符串串对象)。
105+
- "abc" 属于字符串串字⾯面量量,因此编译时期会在 String Pool 中创建⼀一个字符串串对象,指向这个 "abc"
106+
字符串串字⾯面量量;
107+
- ⽽而使⽤用 new 的⽅方式会在堆中创建⼀一个字符串串对象。
108+
109+
创建⼀一个测试类,其 main ⽅方法中使⽤用这种⽅方式来创建字符串串对象。
110+
```java
111+
public class NewStringTest {
112+
public static void main(String[] args) {
113+
String s = new String("abc");
114+
}
115+
}
116+
```
117+
118+
使⽤用 javap -verbose 进⾏行行反编译,得到以下内容:
119+
```java
120+
// ...
121+
Constant pool:
122+
// ...
123+
#2 = Class #18 // java/lang/String
124+
#3 = String #19 // abc
125+
// ...
126+
#18 = Utf8 java/lang/String
127+
#19 = Utf8 abc
128+
// ...
129+
130+
public static void main(java.lang.String[]);
131+
descriptor: ([Ljava/lang/String;)V
132+
flags: ACC_PUBLIC, ACC_STATIC
133+
Code:
134+
stack=3, locals=2, args_size=1
135+
0: new #2 // class java/lang/String
136+
3: dup
137+
4: ldc #3 // String abc
138+
6: invokespecial #4 // Method java/lang/String."
139+
<init>":(Ljava/lang/String;)V
140+
9: astore_1
141+
// ...
142+
```
143+
144+
在 Constant Pool 中,#19 存储这字符串串字⾯面量量 "abc",#3 是 String Pool 的字符串串对象,它指向 #19
145+
这个字符串串字⾯面量量。在 main ⽅方法中,0: ⾏行行使⽤用 new #2 在堆中创建⼀一个字符串串对象,并且使⽤用 ldc #3
146+
将 String Pool 中的字符串串对象作为 String 构造函数的参数。
147+
以下是 String 构造函数的源码,可以看到,在将⼀一个字符串串对象作为另⼀一个字符串串对象的构造函数参数
148+
时,并不不会完全复制 value 数组内容,⽽而是都会指向同⼀一个 value 数组。
149+
150+
```java
151+
public String(String original) {
152+
this.value = original.value;
153+
this.hash = original.hash;
154+
}
155+
```

0 commit comments

Comments
 (0)