您的位置:首页 > 编程语言 > Java开发

重拾Java--功底篇之String

2017-10-18 22:16 204 查看
今天看书看到这样一段代码,感觉十分有趣,在这放一下

private static void test(){
String a = "a" + "b";
String b = "ab";
System.out.println(a == b);
}


呐尼,这边怎么用了”==”,不是应该用equals()么?

那么其实,这段代码运行的最终结果是true,如果你了解原理,这篇文章完全可以跳过,如果是猜的小伙伴,有兴趣可以继续往下看一看

想了解为什么会是true,需要了解以下几个知识点:

1.“==”是做什么的?

2.equals()呢?

3.a和b在内存中是什么样存在的?

4.编译时的优化方案

==

首先,”==”在Java中,原始类型如byte、short、int、long、float、double、boolean、char都是直接比较它们的值是否相等,这个不用多说。

但如果是引用类型的对象,那么比较的其实是两个对象的地址。

equals()

equals()方法在jdk源码的Object类中被定义,它可以被重写。

来看下equals()在Object类中的实现:

public boolean equals(Object obj) {
return (this == obj);
}


原来源码的原始实现用的就是==比较两个对象的地址是否一致,so easy。那么再来看下String类中的equals方法是怎么样的呢?

public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}


大致看一下代码,分为如下几个步骤:

1. 先判断两个对象地址是否相同,如果地址相同,则返回true

2. 再判断传入对象是否为String,若不是则返回false

3. 判断传入的String长度与当前String是否一致,若不一致则返回false

4. 循坏匹配两个String的每个字符是否相等,若不相等,返回false

5. 直到所有字符比较完成,返回true

好了,现在理解了String类中的equals如何工作了

hashCode()

讲到equals()不得不提一下hashCode(),这是一个Object类提供的native(本地)方法,作用是获取对象的hashCode,它的返回值与System.identityHashCode(Obj)一致。是一组由对象头部一部分二进制位组成的数字,用于标识该对象,但绝不等价于地址。这个hashCode主要在HashMap、HashSet等集合类中的对象写入和查找等算法中用于算法快速定位数据之用。

Ps:在JDK1.7中,如果Hash相关的集合的key是String类型,不再使用hashCode,而是用一种hash32属性。

编译时优化

JVM有时会在编译时对代码进行自动优化,如针对代码
String a = "a" + "b"
,因为”a”和”b”都是常量,他们都储存在常量池中,在编译时其实已经转化成了
String a = "ab"
,无须运行时再计算,同样的道理还有
int i = 1 + 3
,编译时自动优化为
int i = 4


当然编译器做的优化远远不止这些,这边只是稍微提及一下。

String的”+”操作

这边稍微瞄一眼String的”+”操作的工作原理,例如代码
String b = a + "b"
,其中a是一个String类型的字符串,因为a是一个变量,因此这段代码编译好之后是这个样子滴:

StringBuilder temp = new StringBuilder();
temp.append(a).append("b");
String b = temp.toString();


关于StringBuilder类的append源码在这就不分析了。(源码什么的 还是很有趣的!)

这边提一个
intern()
方法,这个方法的源码注释是这个样子的

* @return  a string that has the same contents as this string, but is
*          guaranteed to be from a pool of unique strings.


大致意思就是,返回一个与当前字符串内容相同,且在Perm Gen(永久代,即内存的永久保存区域)中保证全局唯一的字符串。

wtf,这是什么意思呢?

首先,Perm Gen是常量池中的一块,它对于同一个值的字符串保证全局唯一。如果一个字符串调用intern(),JVM首先会去常量池中通过equals()选择等值的String,若存在,返回常量池中这个String的地址,如果未找到,会创建等值的字符串,再返回新创建空间的地址。

到这里,有点小累,来个例题放松放松吧

public class test {
public static String getA(){return "a";}
public static void main(String[] args) {
String a = "a";
final String _a = "a";
String b = a + "b";
String c = _a + "b";
String d = getA() + "b";
String e = new String(b);

String compare = "ab";
System.out.println(b == compare);
System.out.println(c == compare);
System.out.println(d == compare);
System.out.println(e == compare);
System.out.println(d.intern() == compare);
System.out.println(e.intern() == compare);
System.out.println(e.intern() == d.intern());
}
}


答案是:
false true false false true true true
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java