Java 源码阅读 - String

String 类型看起来简单,实际上背后的复杂性基本可以涵盖了整个 Java 设计,涉及到设计模式(不可变对象)、缓存(String Pool 的理念)、JVM(String Pool 在 JVM 的模块)等。对 String 了解的多少可以直接体现一个人 Java 乃至对程序设计的水平。

以前真的是管中窥豹。

常见面试题

Q

  • 基础题目

    • String 可以被继承吗?(语法)
    • String a = "str", b = "str", a == b 吗?(JVM 中的 String Pool)
    • String a = new String("str"), b = new String("str"),a == b 吗?(引用)
    • String、 StringBuffer、 StringBuilder 有什么区别?(类库)
  • 比较高级的题目

    • String 设计成不可变类有什么好处?(设计模式)
    • "s" + "tr" == "str" 吗?(JVM 编译期优化)
    • JDK 8 中,String str1 = new StringBuilder("ja").append("va").toString(),str1 == str1.intern() 返回什么结果?(JVM)

A

  • 基础题目

    • 不可以,final
    • 等于,都是从 String Pool 中取,引用相等
    • 不等于,没有从 String Pool 中取
    • String 对比 StringBuffer、StringBuilder:String 不可变,StringBuffer、 StringBuilder 可变;StringBuffer 对比 StringBuilder:StringBuffer 线程安全(synchronize)导致效率低,StringBuilder 线程不安全效率高
  • 比较高级的题目

    • 可以缓存相关字符串(在 String Pool,之后会解释它是什么),节约空间
    • 等于,编译器优化,直接将 "s" + "tr" 优化成 "str",之后从 String Pool 中取,引用相等
    • false,一个是从 String Pool 中取的引用,另一个直接 new

概念:String Pool

英文版:

Thanks to the immutability of Strings in Java, the JVM can optimize the amount of memory allocated for them by storing only one copy of each literal String in the pool. This process is called interning.

When we create a String variable and assign a value to it, the JVM searches the pool for a String of equal value.

If found, the Java compiler will simply return a reference to its memory address, without allocating additional memory.

If not found, it’ll be added to the pool (interned) and its reference will be returned.

简要概况:

String 对象是不可变的,为 String Pool 提供了条件。Java 里可以通过 String.intern() 方法获取在 String Pool 中的对象。

JVM 会创建 String Pool。如果字符串存在于 Pool 中,取 Pool 中的值;如果字符串不存在于 Pool 中,创建然后返回引用。

不可变对象

  • 类被 final 修饰
  • 变量被 final 修饰,在构造器初始化
  • 方法返回的对象为克隆之后新的对象

JVM 对于 String Pool 的处理

  • 在 JDK 6 以及之前,String Pool 存在于 Method Area(方法区,主要保存类的信息,又称永久代),占用 JVM 内存;String Pool 保存字符串是通过先复制再返回复制过后的引用
  • 在 JDK 7 的时候,String Pool 转移到 Heap(实例数据存放的地方),占用 JVM 内存;String Pool 直接记录了第一次字符串出现的引用,以后就返回该引用
  • 在 JDK 8 的时候,String Pool 转移到 Metaspace(相当于 Method Area 另一种实现),占用系统内存;String Pool 直接记录了第一次字符串出现的引用,以后就返回该引用

源码阅读

构造器

最基础的构造器一般是字符数组,通过 clone 的方式,保证了数组修改,字符串内容不会变。

    public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}

下面的构造器简单的复制了之前的字符数组。由于之前的字符数组是克隆的,类本身不会去修改字符数组的内容,所以这里直接复制引用就可以保证不变性。这里并没有走 String Pool,所以类似 "abc" == new String("abc") 的引用地址不同。

    public String(String original) {
this.value = original.value;
this.hash = original.hash;
}

equals 方法首先比较了引用,之后比较了内容。如果都是从 String Pool 里的取的引用,那地址肯定相同;如果不是,则可能不同,需要比较具体内容。

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;
}

hashcode 方法采取了常用 hashcode 算法:若为数组,hash = preHash * 31 + value[i]。注意 hashcode 是会相同的,"Aa"、"BB" 就相同,所以在 HashMap 中,是先比较 hashcode,如果发现有相同的 hashcode 的对象,再用 equals 进行比较。

    public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value; for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}

String 源码分析的更多相关文章

  1. (转)Java中的String为什么是不可变的? -- String源码分析

    背景:被问到很基础的知识点  string  自己答的很模糊 Java中的String为什么是不可变的? -- String源码分析 ps:最好去阅读原文 Java中的String为什么是不可变的 什 ...

  2. string源码分析 ——转载 http://blogs.360.cn/360cloud/2012/11/26/linux-gcc-stl-string-in-depth/

    1. 问题提出 最近在我们的项目当中,出现了两次与使用string相关的问题. 1.1. 问题1:新代码引入的Bug 前一段时间有一个老项目来一个新需求,我们新增了一些代码逻辑来处理这个新需求.测试阶 ...

  3. String源码分析

    前言:String类在日常开发过程中使用频率非常高,平时大家可能看过String的源码,但是真的认真了解过它么,笔者在一次笔试过程中要求写出String的equals方法,瞬间有点懵逼,凭着大致的理解 ...

  4. Java中的String为什么是不可变的? — String源码分析

    原文地址:http://www.importnew.com/16817.html 什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为 ...

  5. String源码分析(1)--哈希篇

    本文基于JDK1.8,首发于公众号:Plus技术栈 让我们从一段代码开始 System.out.println("a" + "b" == "ab&qu ...

  6. 【转】Java中的String为什么是不可变的? -- String源码分析

    什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的.不 ...

  7. Java中的String为什么是不可变的? -- String源码分析

    众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的.不能改变状态的意思是, ...

  8. String 类源码分析

    String 源码分析 String 类代表字符序列,Java 中所有的字符串字面量都作为此类的实例. String 对象是不可变的,它们的值在创建之后就不能改变,因此 String 是线程安全的. ...

  9. Java-Integer源码分析

    除了两种浮点型,剩下的几种基本数据类型的包装类几乎都实现了常量池,有好处用数据的时候直接去拿,没有再去创建,坏处是在程序编译的时候就存入大量数据不管用不用到.下面是一篇很好的文章,很详细,转自:htt ...

随机推荐

  1. oracle 列授权相关测试

    create tablespace liangtbs datafile '/home/oradata/lgjdb/liangtbs01.dbf' size 50m autoextend on;crea ...

  2. jquery的图片异步加载

    <script src="jquery.js"></script> <script src="jquery.lazyload.js" ...

  3. Android自己主动检測版本号及自己主动升级

    步骤: 1.检測当前版本号的信息AndroidManifest.xml-->manifest-->android:versionName. 2.从server获取版本号号(版本号号存在于x ...

  4. [Vue] Conditionally Render DOM Elements in Vue.js (v-if v-else v-show)

    You can use v-if and v-else to display content based on assertions on your data. Similarly, v-show c ...

  5. js进阶 11-8 jquery如何获取元素相对于父元素的位置

    js进阶 11-8  jquery如何获取元素相对于父元素的位置 一.总结 一句话总结:用jquery的position方法,但是使用这个方法的前提是父元素相对定位,子元素绝对定位,否则和offset ...

  6. 适合前端开发的 Chrome 扩展有哪些?(十款)

    适合前端开发的 Chrome 扩展有哪些?(十款) 一.总结 好的插件或者框架对程序员的意义重大. 二.适合前端开发的 Chrome 扩展有哪些?(十款) 掘金是一个高质量的技术社区,从 ECMASc ...

  7. 【t083】买票

    [题目链接]:http://noi.qz5z.com/viewtask.asp?id=t083 [题解] 可以看一下: 钱数很小; 最大才10000; 即使每张票都是1元; 最多也只能买10000张票 ...

  8. JS实现鼠标经过用户头像显示资料卡的效果,可点击

    基于项目的须要.须要制作出例如以下的一种页面效果:当用户鼠标经过好友列表中好友头像时,显示该好友的基本资料.事实上也就是类似QQclient的那种功能. 网上找了非常多代码,基本都实现了鼠标悬浮之后弹 ...

  9. WPF实现射线效果动画

    原文:WPF实现射线效果动画 最近的一个项目中有个需求是:从一个点向其它多个点发出射线,要求这些射线同时发出,同时到达. 我就想到了用WPF的动画来实现.WPF中有Line类用于绘制直线,但这个类中好 ...

  10. 一起学Python:多线程-共享全局变量

    多线程-共享全局变量 from threading import Thread import time g_num = 100 def work1(): global g_num for i in r ...