String 源码分析
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 源码分析的更多相关文章
- (转)Java中的String为什么是不可变的? -- String源码分析
背景:被问到很基础的知识点 string 自己答的很模糊 Java中的String为什么是不可变的? -- String源码分析 ps:最好去阅读原文 Java中的String为什么是不可变的 什 ...
- string源码分析 ——转载 http://blogs.360.cn/360cloud/2012/11/26/linux-gcc-stl-string-in-depth/
1. 问题提出 最近在我们的项目当中,出现了两次与使用string相关的问题. 1.1. 问题1:新代码引入的Bug 前一段时间有一个老项目来一个新需求,我们新增了一些代码逻辑来处理这个新需求.测试阶 ...
- String源码分析
前言:String类在日常开发过程中使用频率非常高,平时大家可能看过String的源码,但是真的认真了解过它么,笔者在一次笔试过程中要求写出String的equals方法,瞬间有点懵逼,凭着大致的理解 ...
- Java中的String为什么是不可变的? — String源码分析
原文地址:http://www.importnew.com/16817.html 什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为 ...
- String源码分析(1)--哈希篇
本文基于JDK1.8,首发于公众号:Plus技术栈 让我们从一段代码开始 System.out.println("a" + "b" == "ab&qu ...
- 【转】Java中的String为什么是不可变的? -- String源码分析
什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的.不 ...
- Java中的String为什么是不可变的? -- String源码分析
众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的.不能改变状态的意思是, ...
- String 类源码分析
String 源码分析 String 类代表字符序列,Java 中所有的字符串字面量都作为此类的实例. String 对象是不可变的,它们的值在创建之后就不能改变,因此 String 是线程安全的. ...
- Java-Integer源码分析
除了两种浮点型,剩下的几种基本数据类型的包装类几乎都实现了常量池,有好处用数据的时候直接去拿,没有再去创建,坏处是在程序编译的时候就存入大量数据不管用不用到.下面是一篇很好的文章,很详细,转自:htt ...
随机推荐
- [React] Update State in React with Ramda's Evolve
In this lesson we'll take a stateful React component and look at how we can refactor our setState ca ...
- p2p网贷系统的架构设计
p2p网贷系统,标准版已经初步完成了. 最近写点总结,也算是分享吧. 简介:p2p网贷系统,是理财类的互联网金融系统.核心功能,就是理财人用户注册,冲钱,然后投标,标到期之后,收到回款.如果不想 ...
- [CSS Flex] Flex direction
flex-direction: main two 'row' or 'column', you can use reverse also.
- [Vue] Import component into page
Components are one of the most powerful features of Vue. Let's take a look at how to write our first ...
- cocos2d-x 3.4 中文乱码解决之道
cocos2dx 中文乱码解决之道 须要引入五个文件 1.iconv.h 2.iconvString.cpp 3.iconvString.h 4.iconv.dll 5.libiconv.lib 完整 ...
- 下载的pod链接失效,build diff: /../Podfile.lock: No such file or directory解决办法
build diff: /../Podfile.lock: No such file or directory 1.终端进入文件路径,执行pod install 2.在工程设置中的Build Phas ...
- centos7 rabbitmq安装/配置
原文:centos7 rabbitmq安装/配置 因为RabbitMQ是由erlang实现的,所以要先安装erlang再安装rabbitMQ 1.先配置yum软件源地址EPEL(EPEL是 ...
- php数学和时间常用函数有哪些(总结表)(看学习视频效率挺高的)(复习)
php数学和时间常用函数有哪些(总结表)(看学习视频效率挺高的)(复习) 一.总结 一句话总结: 1.数学函数常用的6个:max().min().cell().floor().round().mt_r ...
- Xcode7 不能使用http网络请求问题解决
最近使用Xcode 7.0 写代码,发送网路请求提示: App Transport Security has blocked a cleartext HTTP (http://) resource ...
- 控制器管理UINavigationController、UINavigationBar
控制器管理 掌握 控制器以及view的多种创建方式 UINavigationController的简单使用:添加\移除子控制器 UINavigationBar内容的设置 控制器的生命周期方法 Segu ...