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. Android图文具体解释属性动画

    Android中的动画分为视图动画(View Animation).属性动画(Property Animation)以及Drawable动画.从Android 3.0(API Level 11)開始. ...

  2. DYNAMIC CONTEXT SWITCHING BETWEEN ARCHITECTURALLY DISTINCT GRAPHICS PROCESSORS

    FIELD OF INVENTION This invention relates to computer graphics processing, and more specifically to ...

  3. Misultin, Mochiweb, Cowboy, NodeJS 及 Tornadoweb测评

    http://www.oschina.net/translate/a-comparison-between-misultin-mochiweb-cowboy-nodejs-and-tornadoweb ...

  4. ASCII码(转)

    ASCII(American Standard Code for Information Interchange,美国标准信息交换代码)是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧 ...

  5. tombstone问题分析

    tombstone文件包含了发生问题的进程ID信息 I/DEBUG ( 241): pid: 244, tid: 244, name: mediaserver >>> /system ...

  6. 《大话操作系统——扎实project实践派》(8.2)(除了指令集.完)

  7. 微信小程序预览图片

    选择图片时可设置图片是否是原图,图片来源.这用的也挺常见的,比如个人中心中设置头像,可以与wx.upLoadFile()API使用 主要方法: wx.chooseImage(object) wxml ...

  8. An HTTP & HTTP/2 client for Android and Java applications OkHttp

    HTTP is the way modern applications network. It’s how we exchange data & media. Doing HTTP effic ...

  9. spring定时任务.线程池,自定义多线程配置

    定时任务及多线程配置xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=" ...

  10. Android中的后台邮件发送

    一.调用邮件发送工具类进行邮件发送 new Thread(){ public void run() { try { GMailSender sender = new GMailSender( &quo ...