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类详解的更多相关文章

  1. Java String类详解

    Java String类详解 Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它既熟悉又陌生. 类结构: public final ...

  2. java 复习整理(四 String类详解)

    String 类详解   StringBuilder与StringBuffer的功能基本相同,不同之处在于StringBuilder是非线程安全的,而StringBuffer是线程安全的,因此效率上S ...

  3. STL之string类详解

    通过在网站上的资料搜集,得到了很多关于string类用法的文档,通过对这些资料的整理和加入一些自己的代码,就得出了一份比较完整的关于string类函数有哪些和怎样用的文档了!下面先罗列出string类 ...

  4. Java的String类详解

    Java的String类 String类是除了Java的基本类型之外用的最多的类, 甚至用的比基本类型还多. 同样jdk中对Java类也有很多的优化 类的定义 public final class S ...

  5. Java常用类(一)String类详解

    前言 在我们开发中经常会用到很多的常用的工具类,这里做一个总结.他们有很多的方法都是我们经常要用到的.所以我们一定要把它好好的掌握起来! 一.String简介 1.1.String(字符串常量)概述 ...

  6. Java常用类(二)String类详解

    前言 在我们开发中经常会用到很多的常用的工具类,这里做一个总结.他们有很多的方法都是我们经常要用到的.所以我们一定要把它好好的掌握起来! 一.String简介 1.1.String(字符串常量)概述 ...

  7. std::string类详解

    之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必 担心内存是否足够.字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下(甚至 ...

  8. String类详解(1)

    首先String是一个类. 1,实例化String类方法. 1)直接赋值:String name="haha"; 2)通过关键字:String name=new String(&q ...

  9. String类详解,StringBuffer

    先说一下String类的equals()方法. 下面我们先看一段代码: 这段代码输出的结果为: ture true -------------- false 咋看之下貌似Object类比较特别,那么我 ...

随机推荐

  1. 第一篇随笔 - Hello world!

    第一篇随笔 - Hello world! 第一篇随笔 - Hello world! 第一篇随笔 - Hello world! 第一篇随笔 - Hello world! 第一篇随笔 - Hello wo ...

  2. Express基础单词

    访问请求对象(request)或(req) 响应对象(response)或(res) 中间件(middleware) http的请求方法(method) 服务器的路径(path) 路由匹配时的函数(c ...

  3. linux 修改时间和时区

    linux系统时间有两个,一个是硬件时间,即BIOS时间,就是我们进行CMOS设置时看到的时间,另一个是系统时间,是linux系统Kernel时间.当Linux启动时,系统Kernel会去读取硬件时钟 ...

  4. HTML常用标签1

    1 html html:超文本标记(标签)语言 通过标签语言来标记要显示的网页中的各个部分.一套规则,浏览器认识的规则 浏览器渲染的顺序:从上到下,从左到右 对于不同的浏览器,对同一标签可能会有不完全 ...

  5. RS485 VS 20mA 电流环

    RS485采用差分信号负逻辑,+2V-+6V表示“0”,- 6V-- 2V表示“1”.RS485有两线制和四线制两种接线,四线制只能实现点对点的通信方式,现很少采用,现在多采用的是两线制接线方式,这种 ...

  6. JSAP103

    JSAP103 1.节点 1)定义:不是元素,节点是页面中的所有内容(标签,属性,文本),Node.它使得任何标签中的元素获取都十分方便 2)节点的相关属性 可以使用标签即元素点出来,可以使用属性节点 ...

  7. insert /*+append*/为什么会提高性能

    在上一篇的blog中 做了下使用,在归档和非归档下,做数据插入http://blog.csdn.net/guogang83/article/details/9219479.结论是在非归档模式下表设置为 ...

  8. 彻底搞清楚javascript中的require、import和export

    为什么有模块概念 理想情况下,开发者只需要实现核心的业务逻辑,其他都可以加载别人已经写好的模块. 但是,Javascript不是一种模块化编程语言,在es6以前,它是不支持”类”(class),所以也 ...

  9. Mac下的Jenkins安装

    安装方式 1)通过命令行安装   brew install jenkins,可能会遇到先更新 brew 的情况  https://brew.sh/index_zh-cn: 2)通过 pkg 安装,官方 ...

  10. socket.io常用api

    1. 服务端 io.on('connection',function(socket)); 监听客户端连接,回调函数会传递本次连接的socket io.sockets.emit('String',dat ...