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. ubunut下安装ibus_pinyin中文输入法

    ubuntu安装中文输入法,,此处一ibus-pinyin为例为其安装中文输入法,,, 1. 设置(setting)---语言支持(language support)---汉语(chinese),,, ...

  2. hashCode() 和equals() 区别和作用(转)

    出处:https://www.jianshu.com/p/5a7f5f786b75 本章的内容主要解决下面几个问题: 1 equals() 的作用是什么? 2 equals() 与 == 的区别是什么 ...

  3. (10)The secret to great opportunities? The person you haven't met yet

    https://www.ted.com/talks/tanya_menon_the_secret_to_great_opportunities_the_person_you_haven_t_met_y ...

  4. Lagrange 乘子法求最优解

    clc clear syms x y z r1 r2 w f=x^+y^+z^+w^; g1=*x-y+z-w-; g2=x+y-z+w-; h=f-r1*g1 -r2*g2; hx=diff(h,x ...

  5. IntelliJ IDEA 2017版 spring-boot2.0.2 搭建 JPA springboot DataSource JPA环境搭建,JPA注解@ManyToOne使用详情;JPA外键设置

    一.数据库原型 数据库模型如图所示,而现在需要根据数据库模型,建立对应的实体类,这在项目重构老数据库,采用新的框架重构上应该是比较常见的. 数据库脚本如下: CREATE TABLE `bomsub` ...

  6. innerText兼容处理

    转载自:https://www.cnblogs.com/leejersey/p/3520497.html:稍微改了一下和加了一些注释: IE.Safari.Opera和Chrome支持innerTex ...

  7. VIP之Clipper

    裁剪器II提供方法从视频流中选择有效区域并丢弃剩余部分. 指定有效区域的方式是从到边界的偏移量,或者给出有效区左上角的像素坐标和有效区的宽及高度. 裁剪器IP核通过读取Avalon-ST视频流中的控制 ...

  8. C++调用ocx

    1.保证ocx已正常注册,可以使用 2.创建一个C++的命令行程序,在主程序#import "HZ_KevinTest.ocx" no_namespace 生成一次程序,debug ...

  9. mybatis的update操作的几种动态更新

    mybatis是我们开发者常用的dao框架,亿轻巧灵活为特征,在crud操作中,动态更新是常用的操作.我搜集了两种动态更新的sql写法,以备日后备用! 方法1: update loan_product ...

  10. 【repost】DOM CRUD

    //DOM 的 CRUD // c 创建create // 1.直接往body中动态的添加标签(可以是任意类型)document.write('helloWorld');document.write( ...