深入理解String类详解
1、Stringstr = "eee" 和String str = new String("eee")的区别
先看一小段代码,
1 public static void main(String[] args) {
2 String str1 = "eee";
3 String str2 = "eee";
4 String str3 = new String("eee");
5 System.out.println("str1 == str2 is " + (str1 == str2));
6 System.out.println("str1 == str3 is " + (str1 == str3));
7 System.out.println("str1.equals(str2) is " + str1.equals(str2));
8 System.out.println("str1.equals(str3) is " + str1.equals(str3));
9 }
运行结果为:
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角度分析以上代码:
1 String str1 = "eee"; //1、在运行时常量池中创建新的对象"eee",如果常量池中不存在的话;2、栈中创建对象的引用str1
2 String str2 = "eee"; //由于运行时常量池中已经存在该对象,直接在栈中创建对象的引用str2即可。
3 String str3 = new String("eee"); //1、通过new指令,在堆中创建新的对象,2、在栈中创建对象的引用str3。
对象之间通过==来比较,比较的是对象的引用。因此也就不难理解为什么str1 == str2, 而str != str3了。
而equals方法比较的是什么呢?如果类没有重写Object类中equals方法时,比较的也就是对象的引用;如果重写了equals方法,那么就要看重写的方法了。
3、从代码角度分析
在jdk1.8中查看String类的源码,
1 public final class String
2 implements java.io.Serializable, Comparable<String>, CharSequence {
3 private final char value[];
4 private int hash; // Default to 0
5
6 public String(String original) {
7 this.value = original.value;
8 this.hash = original.hash;
9 }
10
11 /** 实际比较的是value[]是否相等 */
12 public boolean equals(Object anObject) {
13 if (this == anObject) {
14 return true;
15 }
16 if (anObject instanceof String) {
17 String anotherString = (String)anObject;
18 int n = value.length;
19 if (n == anotherString.value.length) {
20 char v1[] = value;
21 char v2[] = anotherString.value;
22 int i = 0;
23 while (n-- != 0) {
24 if (v1[i] != v2[i])
25 return false;
26 i++;
27 }
28 return true;
29 }
30 }
31 return false;
32 }
33 }
根据源代码可以看出,String类的equals方法比较的实际是value[]是否相等。根据构造函数以及之前的JVM内存模型,可以分析出str1,str2,str3在内存中关系如下:
可以很容易的理解,str1.equals(str3)为true。
4、不建议String对象作为锁去同步
直接看一个例子,
1 public class StringAsSynchronized {
2 public static class Service {
3 public void print(String stringParam) {
4 try {
5 synchronized (stringParam) {
6 while (true) {
7 System.out.print(Thread.currentThread().getName());
8 Thread.sleep(1000);
9 }
10 }
11 } catch (InterruptedException e) {
12 e.printStackTrace();
13 }
14 }
15 }
16
17 public static class ThreadA extends Thread {
18 private Service service;
19 private String stringA = "synchronized";
20
21 public ThreadA(Service service) {
22 this.service = service;
23 }
24
25 @Override
26 public void run() {
27 service.print(stringA);
28 }
29 }
30
31 public static class ThreadB extends Thread {
32 private Service service;
33 private String stringB = "synchronized";
34
35 public ThreadB(Service service) {
36 this.service = service;
37 }
38
39 @Override
40 public void run() {
41 service.print(stringB);
42 }
43 }
44
45 public static void main(String[] args) {
46 Service service = new Service();
47 ThreadA a = new ThreadA(service);
48 a.setName("A");
49 ThreadB b = new ThreadB(service);
50 b.setName("B");
51 a.start();
52 b.start();
53 }
54 }
运行结果为:AAAAAAAAA。。。。
原因为ThreadA类以及ThreadB类中的成员变量stringA以及stringB指向的是同一个对象。
改正方法为
1、第33行修改为private String stringB = new String("synchronized");
2、更好的做法是不使用String对象用来同步锁。
深入理解String类详解的更多相关文章
- Java String类详解
Java String类详解 Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它既熟悉又陌生. 类结构: public final ...
- java 复习整理(四 String类详解)
String 类详解 StringBuilder与StringBuffer的功能基本相同,不同之处在于StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此效率上S ...
- STL之string类详解
通过在网站上的资料搜集,得到了很多关于string类用法的文档,通过对这些资料的整理和加入一些自己的代码,就得出了一份比较完整的关于string类函数有哪些和怎样用的文档了!下面先罗列出string类 ...
- Java的String类详解
Java的String类 String类是除了Java的基本类型之外用的最多的类, 甚至用的比基本类型还多. 同样jdk中对Java类也有很多的优化 类的定义 public final class S ...
- Java常用类(一)String类详解
前言 在我们开发中经常会用到很多的常用的工具类,这里做一个总结.他们有很多的方法都是我们经常要用到的.所以我们一定要把它好好的掌握起来! 一.String简介 1.1.String(字符串常量)概述 ...
- Java常用类(二)String类详解
前言 在我们开发中经常会用到很多的常用的工具类,这里做一个总结.他们有很多的方法都是我们经常要用到的.所以我们一定要把它好好的掌握起来! 一.String简介 1.1.String(字符串常量)概述 ...
- std::string类详解
之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必 担心内存是否足够.字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下(甚至 ...
- String类详解(1)
首先String是一个类. 1,实例化String类方法. 1)直接赋值:String name="haha"; 2)通过关键字:String name=new String(&q ...
- String类详解,StringBuffer
先说一下String类的equals()方法. 下面我们先看一段代码: 这段代码输出的结果为: ture true -------------- false 咋看之下貌似Object类比较特别,那么我 ...
随机推荐
- UVALive - 4885 Task 差分约束
Task 题目连接: https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page ...
- Ubuntu1404安装eclipse(目的是为了运行python,当然java更可以)
原创文章,不得转载 我是彩印网(www.caiyin.com) 的技术开发人员,在这里首先请允许我做下业务的介绍 彩印网是由北京出彩电子商务有限公司运营的专业印刷电商,集线上购物.支付.设计.制作.配 ...
- GMA Round 1 奇怪的数列
传送门 奇怪的数列 已知数列{$a_n$},$a_1=1$,$a_{n+1}=a_n+\frac{1}{a_n}$,现在需要你估计$a_{233333}$的值,求出它的整数部分即可. 将原等式两边平方 ...
- C. Playing Piano 动态规划
题目意思是给你一个n长度的数字串为a,让你构造一个n长度的数字串b值都为1-5满足以下条件: 正常的dfs暴力构造会超时,我试过了.. 可以开一个二维数组dp[i][j]用来表示b的第i个数字为j是否 ...
- Unity 5.4版本 Application.systemLanguage 失效
最近在上线双语版本(一个包支持中文.英文二种语言)时,遇到一个坑点 if (ToolUtils.isAndroid()) { if (Application.systemLanguage == Sys ...
- EF Core中执行Sql语句查询操作之FromSql,ExecuteSqlCommand,SqlQuery
一.目前EF Core的版本为V2.1 相比较EF Core v1.0 目前已经增加了不少功能. EF Core除了常用的增删改模型操作,Sql语句在不少项目中是不能避免的. 在EF Core中上下文 ...
- 基于Cesium的demo赏析
更新于2019.2.23 Cesium的强大不用多说,所以有很多政府.组织基于cesium做了一些应用,其中不乏有很多优秀的示例,我们大都可以从中获得对自己的项目有益的东西.另:有的网站需要FQ. 官 ...
- CDH下集成spark2.2.0与kafka(四十一):在spark+kafka流处理程序中抛出错误java.lang.NoSuchMethodError: org.apache.kafka.clients.consumer.KafkaConsumer.subscribe(Ljava/util/Collection;)V
错误信息 19/01/15 19:36:40 WARN consumer.ConsumerConfig: The configuration max.poll.records = 1 was supp ...
- PHP 使用POST 获取不到部分数据问题
使用PHP开发的一个项目,在测试阶段客户反馈说数据没有保存成功 而我之前测试是通过的,但按客户的信息上却重现了问题 问题是这样的 客户通过浏览器进行保存,但有些数据已经保存成功,但某些数据却没有保存成 ...
- docker的常用命令汇总
1================================================================================ docker 列出每个容器的IP ...