深入理解String类
1、String str = "eee" 和String str = new String("eee")的区别
先看一小段代码,
public static void main(String[] args) {
String str1 = "eee";
String str2 = "eee";
String str3 = new String("eee");
System.out.println("str1 == str2 is " + (str1 == str2));
System.out.println("str1 == str3 is " + (str1 == str3));
System.out.println("str1.equals(str2) is " + str1.equals(str2));
System.out.println("str1.equals(str3) is " + str1.equals(str3));
}
运行结果为:
str1 == str2 is true
str1 == str3 is false
str1.equals(str2) is true
str1.equals(str3) is true
2、从JVM角度分析
《深入理解Java虚拟机》一书指出,JVM运行时数据区如下:
所有线程共享区域包括:
方法区:用于存储已被虚拟机加载的类信息、常亮、静态变量、即时编译器编译后的代码等数据,以及运行时常量池。
Java堆:在虚拟机启动时创建,存放对象实例,几乎所有的对象实例都在这里分配内存。
线程私有区域包括:
虚拟机栈:用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
本地方法栈:与虚拟机栈类似, 区别主要是本地方法栈为Native方法服务。
程序计数器:一块较小的内存空间,当作当前线程所执行字节码的行号指示器。字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能需要依赖这个计数器来完成。
String是一个不可变对象,可以认为是特殊的常量,因此存在方法区的运行时常量池中,可以被共享使用,以提高效率。
从JVM角度分析以上代码:
String str1 = "eee"; //1、在运行时常量池中创建新的对象"eee",如果常量池中不存在的话;2、栈中创建对象的引用str1
String str2 = "eee"; //由于运行时常量池中已经存在该对象,直接在栈中创建对象的引用str2即可。
String str3 = new String("eee"); //1、通过new指令,在堆中创建新的对象,2、在栈中创建对象的引用str3。
对象之间通过==来比较,比较的是对象的引用。因此也就不难理解为什么str1 == str2, 而str != str3了。
而equals方法比较的是什么呢?如果类没有重写Object类中equals方法时,比较的也就是对象的引用;如果重写了equals方法,那么就要看重写的方法了。
3、从代码角度分析
在jdk1.8中查看String类的源码,
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[];
private int hash; // Default to 0 public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
/** 实际比较的是value[]是否相等 */
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;
}
}
根据源代码可以看出,String类的equals方法比较的实际是value[]是否相等。根据构造函数以及之前的JVM内存模型,可以分析出str1,str2,str3在内存中关系如下:
可以很容易的理解,str1.equals(str3)为true。
4、不建议String对象作为锁去同步
直接看一个例子,
public class StringAsSynchronized {
public static class Service {
public void print(String stringParam) {
try {
synchronized (stringParam) {
while (true) {
System.out.print(Thread.currentThread().getName());
Thread.sleep(1000);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static class ThreadA extends Thread {
private Service service;
private String stringA = "synchronized"; public ThreadA(Service service) {
this.service = service;
} @Override
public void run() {
service.print(stringA);
}
} public static class ThreadB extends Thread {
private Service service;
private String stringB = "synchronized"; public ThreadB(Service service) {
this.service = service;
} @Override
public void run() {
service.print(stringB);
}
} public static void main(String[] args) {
Service service = new Service();
ThreadA a = new ThreadA(service);
a.setName("A");
ThreadB b = new ThreadB(service);
b.setName("B");
a.start();
b.start();
}
}
运行结果为:AAAAAAAAA。。。。
原因为ThreadA类以及ThreadB类中的成员变量stringA以及stringB指向的是同一个对象。
改正方法为
1、第33行修改为private String stringB = new String("synchronized");
2、更好的做法是不使用String对象用来同步锁。
深入理解String类的更多相关文章
- Java基础系列2:深入理解String类
Java基础系列2:深入理解String类 String是Java中最为常用的数据类型之一,也是面试中比较常被问到的基础知识点,本篇就聊聊Java中的String.主要包括如下的五个内容: Strin ...
- 跟着刚哥梳理java知识点——深入理解String类(九)
一.String类 想要了解一个类,最好的办法就是看这个类的实现源代码,来看一下String类的源码: public final class String implements java.io.Ser ...
- 深入理解String类详解
1.Stringstr = "eee" 和String str = new String("eee")的区别 先看一小段代码, 1 public static ...
- jdk源码理解-String类
String类的理解 简记录一下对于jdk的学习,做一下记录,会持续补充,不断学习,加油 1.String的hash值的计算方法. hash值的计算方法多种多样,jdk中String的计算方法如下,比 ...
- 【C++】从设计原理来看string类
1.一些C++基础知识 模板类string的设计属于底层,其中运用到了很多C++的编程技巧,比如模板.迭代器.友元.函数和运算符重载.内联等等,为了便于后续理解string类,这里先对涉及到的概念做个 ...
- 从C# String类理解Unicode(UTF8/UTF16)
上一篇博客:从字节理解Unicode(UTF8/UTF16).这次我将从C# code 中再一次阐述上篇博客的内容. C# 代码看UTF8 代码如下: string test = "UTF- ...
- 深入理解Java String类(综合)
在Java语言了中,所有类似“ABC”的字面值,都是String类的实例:String类位于java.lang包下,是Java语言的核心类,提供了字符串的比较.查找.截取.大小写转换等操作:Java语 ...
- String类的深入理解
String不是基本数据类型,String和8种包装类型是不可变类.String和8种基本数据类型采用值传递. 关于方法区中的常量区和class文件中的常量区的关系,参考:https://www.cn ...
- String Buffer和String Builder(String类深入理解)
String在Java里面JDK1.8后它属于一个特殊的类,在创建一个String基本对象的时候,String会向“ 字符串常量池(String constant pool)” 进行检索是否有该数 ...
随机推荐
- 使用policheck 检测
Policheck is a profing and testing tool for sensitive terminology and helps in ensuring thattrustwor ...
- my.ini优化mysql数据库性能的十个参数(推荐)
(1).max_connections:允许的同时客户的数量.增加该值增加 mysqld 要求的文件描述符的数量.这个数字应该增加,否则,你将经常看到 too many connections 错误. ...
- mysql的myBatis,主键自增设置
方法一: insert id="insert" parameterType="Person" useGeneratedKeys="true" ...
- Mysql正常启动之后默认使用的文件
--basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --plugin-dir=/usr/local/mysql/lib/plugi ...
- IntellJ IDEA2017 springboot2.0.2 替代@SpringBootApplication方式
如果不想用@SpringBootApplication,那么可以用@EnableAutoConfiguration 和@ComponentScan替代@SpringBootApplication 详情 ...
- 预装apk
一般是在device/rockchip/ LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := LanguageSetLOC ...
- WebGIS实现在线要素编辑之ArcGIS Server 发布Feature Service 过程解析
WebGIS实现在线要素编辑之ArcGIS Server 发布Feature Service 过程解析 FeatureService也称要素服务,其最大的好处就是支持在线要素编辑,并将编辑同步更新到后 ...
- Kindeditor图片粘贴上传(chrome)
kindeditor4.1.x版本已支持图片批量上传,不过传统的选文件上传的方式依然效率低下. 很多时候,编辑人员可能需要将一个文档中图片上传到网上,那么,按照传统的上传方法,他必须先将图片另存为到本 ...
- 开源C++版本CGI库CGICC入门
原发布在ChinaUnix,但未自动搬迁过来:http://blog.chinaunix.net/uid-20682147-id-4895772.html PDF版本:https://files-cd ...
- ibatis.net之我的调整:Update语句的动态set字段
动态Update语句 如果Map中指定多个字段 <update id="UpdateStaff"> update Staff set Name=#Name#,InDat ...