Algorithms I - Module 0: Java Review
Value Equality v.s. Reference Equality
Type | Reference Equality== 比较 | Value Equalityequals() 比较 |
---|---|---|
Primitive | value | N/A |
Reference | address | contents |
基本类型不需要区分值和引用,因为它们本身就是值,而引用类型存储的是对象的地址,所以需要明确区分两者的比较方式。
字符串比较
Java 的字符串池(String Pool)
在 Java 中,字符串池(String Pool)是 JVM 维护的一块特殊内存区域,用于存储字符串字面量(即直接写在代码中的 "This is a string."
)。如果一个字符串字面量已经存在于池中,那么新的相同字面量不会创建新的对象,而是直接复用已有的对象。
1 |
|
System.out.println(literal == anotherLiteral); // true
这里 literal
和 anotherLiteral
直接指向同一个字符串池中的 "This is a string."
,所以 ==
比较返回 true
。
new String()
总是创建新的对象
当使用 new String("This is a string.")
时,JVM 无论字符串池中是否有该字符串,都会创建一个新的 String
对象。
1 |
|
System.out.println(literal == object); // false
这里 literal
存储的是字符串池中的对象,而 object
是 new
关键字创建的一个新对象,它存储在堆(Heap) 中,而不是字符串池中。因此 literal == object
返回 false
。
equals()
用于内容比较
如果要比较 String
的内容,应该使用 equals()
方法:
1 |
|
equals()
方法会逐个比较字符串的字符内容,而 ==
只是比较对象的引用地址。
如何让 new String()
的对象和池中的字符串相等
如果你想让 new String()
创建的对象和池中的字符串共享引用,可以使用 intern()
方法:
1 |
|
intern()
方法会检查字符串池中是否已经存在该字符串,如果存在,就返回池中的对象;否则,它会把该字符串加入字符串池,并返回该对象的引用。
总结
1 |
|
比较表达式 | 结果 | 原因 |
---|---|---|
literal == object |
false |
literal 是字符串池中的对象,object 是 new String() 创建的对象 |
literal == "This is a string." |
true |
"This is a string." 在编译时已存入字符串池,literal 也是该池的引用 |
"This is a string." == "This is a string." |
true |
直接使用的字面量,指向同一个字符串池中的对象 |
object == "This is a string." |
false |
object 是 new String() 创建的,存于堆中,而 "This is a string." 存于字符串池 |
object == new String("This is a string.") |
false |
new String() 每次都会创建新的对象,两个对象的引用不同 |
Pass by Value/Reference
🔧总结
✅ Java 是 Pass by Value(按值传递)
但这“值”可以是两种类型:
- 基本类型(primitive):传的是实际值的副本。
- 引用类型(object):传的是引用的副本(也就是说,这个引用是指向对象的地址的一个拷贝)。
基本类型(int)
1 |
|
count
是基本类型,传给helper
后,x
拿到的是一个 复制的值。- 在
helper
中对x
做的任何修改,不会影响main()
里的count
。 - 所以输出仍是
0
。
创建了新对象
1 |
|
count
是一个引用变量,指向某个对象。- 传给
helper
后,x
拿到的是这个“引用”的副本,也指向原来的对象。 - 但你在
helper
中 新建了一个对象,并让 x 指向它,这只是改了x
的指向,并没有改 count 的指向。 - 所以
main()
里的count
还是原来的对象,item
是0
。
修改了对象内容
1 |
|
- 没有创建新对象,而是通过引用修改了原对象的内容。
- 所以
count.getItem()
的值真的变成了 1。