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 ...
随机推荐
- 从头认识Spring-2.3 注解装配-@autowired(5)-限定器@Qualifier(1)
这一章节我们来具体讨论一下配合@autowired一起使用的限定器@Qualifier. 1.domain(重点) 蛋糕类: package com.raylee.my_new_spring.my_n ...
- 辛星浅析yaf框架中的类的自己主动载入问题
因为公司非常多项目都是基于yaf的,而非常多刚接触yaf的朋友问的第一个问题就是:yaf的自己主动载入是依照什么规则来的. 鉴于此.于是我特别开了一篇博文来记录一下. 首先在yaf中.models文件 ...
- spring boot + gradle + mybatis
使用intelliJ创建 spring boot + gradle + mybatis站点 Spring boot作为快速入门是不错的选择,现在似乎没有看到大家写过spring boot + gr ...
- WPF入门(四)->线形区域Path内容填充之填充图(ImageBrush)
原文:WPF入门(四)->线形区域Path内容填充之填充图(ImageBrush) 前面我们提到了LinearGradientBrush可以用来画渐变填充图,那么我们同时也可以使用ImageBr ...
- tomcat7,8 centos7 配置apr极好教程
转自:http://blog.csdn.net/remote_roamer/article/details/51719891 第一次我自己是用的yum安装apr, apr-utils, tomcat- ...
- 关于JDBC连接数据库时出现的Public Key Retrieval is not allowed错误
问题描述 最近在学习MyBatis框架,参考官方的文档通过配置文件的方式已经实现了通过Configuration配置文件和mapper映射文件访问mysql8数据库,于是想试试不使用XML文件去构建S ...
- 用C语言编写简单的病毒
[摘要]在分析病毒机理的基础上,用C语言写了一个小病毒作为实例,用TURBOC2.0实现. [Abstract] This paper introduce the charateristic of t ...
- 苹果抛弃的芯片公司Imagination被中资49亿溢价收购
原标题:中国资本Canyon Bridge出资5.5亿英镑收购Imagination芯片 来源:观察者网 对于一家手机硬件公司来说,被苹果看上可谓是“一夜之间,鸡犬升天”.但是如果被苹果抛弃了呢?那可 ...
- 一个里程碑,新网站实现全站https
本地验证node服务没问题后,上传到阿里云服务器上,发现无法访问.一开始以为是SSL证书有问题,去腾讯云SSL证书重新下载,还是不行.然后改node应用文件代码app.js,猜测是crt证书应该改成p ...
- Dojo第一节:学会使用firebug对js,Dojo进行调适
内容概要: 学会使用firebug的基本功能 1. 简介:Firebug是Firefox的一个插件,用来对js代码进行调适的工具. (官方废话:Firebug是firefox下的一个插件,可以调试全部 ...