深入理解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)” 进行检索是否有该数 ...
随机推荐
- Softmax && Cross-entropy Error
softmax 函数,被称为 归一化指数函数,是sigmoid函数的推广. 它将向量等比压缩到[0, 1]之间,所有元素和为1. 图解: Example: softmax([1, 2, 3, 4, 1 ...
- lambda表达式,变量作用域
# lambda表达式 def filter_lt(predidcate,lt): result=[] for elem in lt: if predidcate(elem): result.appe ...
- Codeforces Round #543 (Div. 2) D 双指针 + 模拟
https://codeforces.com/contest/1121/problem/D 题意 给你一个m(<=5e5)个数的序列,选择删除某些数,使得剩下的数按每组k个数以此分成n组(n*k ...
- centos7 新增ip
1.进入network-scripts目录:cd /etc/sysconfig/network-scripts/ 2.复制ifcfg-eth0: cp ifcfg-eth0 ifcfg-eth0:0 ...
- C语言三种方法调用数组
#include <stdio.h> /********************************* * 方法1: 第一维的长度可以不指定 * * 但必须指定第二维的长度 * *** ...
- 简单MVC实现增删改查
反射工具类RelfectionUtils package Utils; import java.lang.reflect.Field; import java.lang.reflect.Invocat ...
- char类型
1.JAVA中,char占2字节,16位.可在存放汉字 2.char赋值 char a='a'; //任意单个字符,加单引号. char a='中';//任意单个中文字,加单引号. char a=1 ...
- virtualbox centos 连接网络
一.设置网络 设置 -> 网络 -> 连接方式:桥接网卡.设置当前连网络的界面名称.接入网线打勾 二.开启eth0 vi /etc/sysconfig/network-scripts/if ...
- 绑定弹窗事件最好的方法,原生JS和JQuery方法
使用jQuery ui = { $close: $('.close') , $pop: $('.pop') , $topopBtn: $('.topop-btn') , $popbtnArea: $( ...
- 20155326 2016-2017-2《Java程序设计》课程总结
20155326 2016-2017-2<Java程序设计>课程总结 (按顺序)每周作业链接汇总 20155326刘美岑的第一次作业:第一次写博客,写下了对java的期待 20155326 ...