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

  1. Java基础系列2:深入理解String类

    Java基础系列2:深入理解String类 String是Java中最为常用的数据类型之一,也是面试中比较常被问到的基础知识点,本篇就聊聊Java中的String.主要包括如下的五个内容: Strin ...

  2. 跟着刚哥梳理java知识点——深入理解String类(九)

    一.String类 想要了解一个类,最好的办法就是看这个类的实现源代码,来看一下String类的源码: public final class String implements java.io.Ser ...

  3. 深入理解String类详解

    1.Stringstr = "eee" 和String str = new String("eee")的区别 先看一小段代码, 1 public static ...

  4. jdk源码理解-String类

    String类的理解 简记录一下对于jdk的学习,做一下记录,会持续补充,不断学习,加油 1.String的hash值的计算方法. hash值的计算方法多种多样,jdk中String的计算方法如下,比 ...

  5. 【C++】从设计原理来看string类

    1.一些C++基础知识 模板类string的设计属于底层,其中运用到了很多C++的编程技巧,比如模板.迭代器.友元.函数和运算符重载.内联等等,为了便于后续理解string类,这里先对涉及到的概念做个 ...

  6. 从C# String类理解Unicode(UTF8/UTF16)

    上一篇博客:从字节理解Unicode(UTF8/UTF16).这次我将从C# code 中再一次阐述上篇博客的内容. C# 代码看UTF8 代码如下: string test = "UTF- ...

  7. 深入理解Java String类(综合)

    在Java语言了中,所有类似“ABC”的字面值,都是String类的实例:String类位于java.lang包下,是Java语言的核心类,提供了字符串的比较.查找.截取.大小写转换等操作:Java语 ...

  8. String类的深入理解

    String不是基本数据类型,String和8种包装类型是不可变类.String和8种基本数据类型采用值传递. 关于方法区中的常量区和class文件中的常量区的关系,参考:https://www.cn ...

  9. String Buffer和String Builder(String类深入理解)

      String在Java里面JDK1.8后它属于一个特殊的类,在创建一个String基本对象的时候,String会向“ 字符串常量池(String constant pool)” 进行检索是否有该数 ...

随机推荐

  1. HBuilder中ios打包

    参考:http://ask.dcloud.net.cn/article/152 在ios端钥匙串双击(教程上是双击)导入证书时候,可能会报错,直接把证书文件拖入到keychain的登录里就解决了. 1 ...

  2. P3834 【模板】可持久化线段树 1(主席树)

    #include <bits/stdc++.h> #define read read() #define up(i,l,r) for(int i = (l);i <= (r);i++ ...

  3. 用sql 生成2016年全年的日期

    select to_char(日期,'yyyy-mm-dd') from( select to_date('2016-01-01','yyyy-mm-dd') + level 日期 from dual ...

  4. 牛客训练四:Applese 走方格(细节)

    题目链接:传送门 思路:主要是n=1,m=2或者n=2,m=1时,不是-1. #include<iostream> #include<cstdio> #include<c ...

  5. Servlet中(Session、cookies、servletcontext)的基本用法

    /req: 用于获得客户端(浏览器)的信息 //res: 用于向客户端(浏览器)返回信息 1.session的设置:            //得到和req相关联的session,如果没有就创建ses ...

  6. s4-5 以太网帧

    以太网所处的层次 IEEE 802.3/以太网MAC子层协议  IEEE802.3协议描述了运行在各种介质上1 Mb/s~10 Mb/s的1- 持续CSMA/CD协议的局域网标准.  很多人对以太 ...

  7. @RequestBody jackson解析复杂的传入值的一个坑;jackson解析迭代数组;jackson多重数组;jakson数组

    一.实际开发的一个问题. 传入一个json数组,数组中还嵌套数组,运用springboot+Jpa框架,@RequestBody注解传入数据 Controller @ApiOperation(valu ...

  8. IntelliJ IDEA 2017版 编译器使用学习笔记(八) (图文详尽版);IDE快捷键使用;IDE代码重构(寻找修改痕迹)

    git集成: 快速找到版本控制器中某段代码的作者 一.annotate            选中某行代码,右键,选择annotate,鼠标放于其上就会显示注释    二.移动所有改动之处: prev ...

  9. 好文推荐系列-------(5)js模块化编程

    本文主要来源于阮一峰的<Javascript模块化编程>系列文章整合,原文地址:http://www.ruanyifeng.com/blog/2012/10/javascript_modu ...

  10. python advanced programming ( II )

    面向对象编程 简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数.数据封装.继承和多态是面向对象的三大特点. 在Python中,所有数据类型都可以视为对 ...