java字符串缓冲池分析

java的虚拟机在内存中开辟出一块单独的区域,用来存储字符串对象,这块内存区域被称为字符串缓冲池。那个java的字符串缓冲池是如何工作的呢?

String a = "abc";
String b = "abc";
String c = new String("xyz");

例如上边的代码:

String a = “abc”;

创建字符串的时候先查找字符串缓冲池中有没有相同的对象,如果有相同的对象就直接返回该对象的引用,如果没有相同的对象就在字符串缓冲池中创建该对象,然后将该对象的应用返回。对于这一步而言,缓冲池中没有abc这个字符串对象,所以首先创建一个字符串对象,然后将对象引用返回给a。

String b = “abc”;

这一句也是想要创建一个对象引用变量b使其指向abc这一对象。这时,首先查找字符串缓冲池,发现abc这个对象已经有了,这是就直接将这个对象的引用返回给b,此时a和b就共用了一个对象abc,不过不用担心,a改变了字符串而影响了b,因为字符串都是常量,一旦创建就没办法修改了,除非创建一个新的对象。

String c = new String(“xyz”);(这种构造方法的实现见附录)

查找字符串缓冲池发现没有xyz这个字符串对象,于是就在字符串缓冲池中创建了一个zyx对象然后再将引用返回。

从上边的分析可以看出,当new一个字符串时并不一定是创建了一个新的对象,有可能是与别的引用变量共同使用了同一个对象。下面看几个常见的有关字符串缓冲池的问题。

到底创建了几个字符串对象

        String a = "abc";
        String b = "abc";
        String c = new String("xyz");
        String d = new String("xyz");
        String e="ab"+"cd";

这个程序与上边的程序比较相似,我们分比来看一下:

String a = “abc”;这一句由于缓冲池中没有abc这个字符串对象,所以会创建一个对象;String b = “abc”;由于缓冲池中已经有了abc这个对象,所以不会再创建新的对象;String c = new String(“xyz”);由于没有xyz这个字符串对象,所以会首先创建一个xyz的对象,然后这个字符串对象由作为String的构造方法,在内存中(不是缓冲池中)又创建了一个新的字符串对象,所以一共创建了两个对象;String d = new String(“xyz”);省略了创建一个对象的过程,所以只创建了一个对象;String e=”ab”+”cd”;由于常量的值在编译的时候就被确定了。所以这一句等价于String e=”abcd”;创建了一个对象

所以创建的对象的个数分别是:1,0,2,1,1

到底相等不相等

我们在学习java时就知道两个字符串对象相等的判断要用equal而不能使用==,但是学习了字符串缓冲池以后,应该知道为什么不能用==,什么情况下==和equal是等价的,首先,必须知道的是,==比较的是两个对象的内存地址是否相等,下面我们就通过几个程序来看一下:

public static void main(String[] args) {
        String s1 = "Monday";
        String s2 = "Monday";
        if (s1 == s2)
            System.out.println("s1 == s2");
        else
            System.out.println("s1 != s2");
    }

输出结果:s1 == s2

分析:通过上边的介绍字符串缓冲池,我们知道s1和s2都是指向字符串缓冲池中的同一个对象,所以内存地址是一样的,所以用==可以判断两个字符串是否相等。

public static void main(String[] args) {
        String s1 = "Monday";
        String s2 = new String("Monday");
        if (s1 == s2)
            System.out.println("s1 == s2");
        else
            System.out.println("s1 != s2");
        if (s1.equals(s2))
            System.out.println("s1 equals s2");
        else
            System.out.println("s1 not equals s2");
    } 

输出结果:s1 != s2

s1 equals s2

分析:由上边的分析我们知道,String s2 = new String(“Monday”);这一句话没有在字符串缓冲池中创建新的对象,但是会在内存的其他位置创建一个新的对象,所以s1是指向字符串缓冲池的,s2是指向内存的其他位置,两者的内存地址不同的。

public static void main(String[] args) {
        String s1 = "Monday";
        String s2 = new String("Monday");
        s2 = s2.intern();
        if (s1 == s2)
            System.out.println("s1 == s2");
        else
            System.out.println("s1 != s2");
        if (s1.equals(s2))
            System.out.println("s1 equals s2");
        else
            System.out.println("s1 not equals s2");
    }

输出结果:s1 == s2

s1 equals s2

分析:先来说说intern()这个方法的作用吧,这个方法的作用是返回在字符串缓冲池中的对象的引用,所以s2指向的也是字符串缓冲池中的地址,和s1是相等的。

public static void main(String[] args) { 

        String Monday = "Monday";
        String Mon = "Mon";
        String  day = "day";
        System.out.println(Monday == "Mon" + "day");
        System.out.println(Monday == "Mon" + day);  

    }

输出结果:true

false

分析:第一个为什么等于true我们已经说过了,因为两者都是常量所以在编译阶段就已经能确定了,在第二个中,day是一个变量,所以不能提前确定他的值,所以两者不相等,从这个例子我们可以看出,只有+连接的两边都是字符串常量时,引用才会指向字符串缓冲池,都则都是指向内存中的其他地址。

public static void main(String[] args) { 

        String Monday = "Monday";
        String Mon = "Mon";
        final String  day = "day";
        System.out.println(Monday == "Mon" + "day");
        System.out.println(Monday == "Mon" + day);  

    }

输出结果:true

true

分析:加上final后day也变成了常量,所以第二句的引用也是指向的字符串缓冲池。

附录

java源码中对于String a = new String(”abc”);这种构造方法的实现

public String(String original) {
        this.value = original.value;
        this.hash = original.hash;
    }

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-05 17:30:42

java字符串缓冲池分析的相关文章

java 字符串内存分配的分析与总结

经常在网上各大版块都能看到对于java字符串运行时内存分配的探讨,形如:String a = "123",String b = new String("123"),这两种形式的字符串是存放在什么地方的呢,其实这两种形式的字符串字面值"123"本身在运行时既不是存放在栈上,也不是存放在堆上,他们是存放在方法区中的某个常量区,并且对于相同的字符串字面值在内存中只保留一份.下面我们将以实例来分析. 1.==运算符作用在两个字符串引用比较的两个案例: p

常用 Java 静态代码分析工具的分析与比较

转载自: http://www.oschina.net/question/129540_23043 简介: 本文首先介绍了静态代码分析的基本概念及主要技术,随后分别介绍了现有 4 种主流 Java 静态代码分析工具 (Checkstyle,FindBugs,PMD,Jtest),最后从功能.特性等方面对它们进行分析和比较,希望能够帮助 Java 软件开发人员了解静态代码分析工具,并选择合适的工具应用到软件开发中. 引言 在 Java 软件开发过程中,开发团队往往要花费大量的时间和精力发现并修改代

Java线程Dump分析工具--jstack

jstack用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息,如果是在64位机器上,需要指定选项"-J-d64",Windows的jstack使用方式只支持以下的这种方式:      jstack [-l][F] pid      如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程序是如何崩溃和在程序何处发生问题.另外,jstack工具还可

深入Java字符串

深入Java字符串 Java字符串类(java.lang.String)是Java中使用最多的类,也是最为特殊的一个类,很多时候,我们对它既熟悉又陌生. 一.从根本上认识java.lang.String类和String池 首先,我建议先看看String类的源码实现,这是从本质上认识String类的根本出发点.从中可以看到: 1.String类是final的,不可被继承.public final class String. 2.String类是的本质是字符数组char[], 并且其值不可改变.pr

【java解惑】java字符串替换方法使用

    如下代码: public class Example020 { public static void main(String[] args) { String separator = File.separator; String clazzName = Example020.class.getName(); String rs1 = clazzName.replace(".", separator); // 方法1 String rs2 = clazzName.replaceA

Java之内存分析和String对象

http://www.cnblogs.com/devinzhang/archive/2012/01/25/2329463.html Java中内存分析: 栈(Stack) :存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中). 堆(heap):存放所有new出来的对象. 常量池(constant pool):在堆中分配出来的一块存储区域,存放储显式的String常量和基本类型常量(float.int等).另外

Java class文件分析工具 -- Classpy

Classpy Classpy是一个图形化的class文件分析工具,功能和javap类似,界面主要参考了Java Class Viewer: 为什么要重新创造轮子? 写这个工具花了将近一周的时间,那么为什么要浪费时间重新发明一个轮子呢?主要是因为下面几点原因: 通过自己写一个class解析器,可以彻底理解class文件格式和字节码 尝鲜Java8和JavaFX 8 Java Class Viewer比较老,不支持新的class文件格式 可以结合javap和Java Class Viewer的优点

004 Java字符串的几个特性

在本系列教材的上一篇(003 Java字符串)中,对Java语言中String类的一些基本情况和整体架构进行了讲解和分析,相信大家已经很好地掌握了.本篇教程主要是补充一些String类的重要特性,帮助大家避免掉使用String过程中的一些陷阱. 首先,补充一个在JDK中使用非常频繁的概念:不可变类.所谓的不可变类是指该类的对象在生成以后就不会被改变了,关于不可变类的优点.缺点,特别是在Java并发编程时的优势,此处暂时略过不讲.那么如何定义一个不可变类呢?如果你有仔细观察String类的源码,你

java字符串解析

java的虚拟机在内存中开辟出一块单独的区域,用来存储字符串对象,这款内存区域被称为字符串缓冲池. //创建字符串的时候先查找字符串缓冲池中没相同的对象,如果相同的对象就直接返回改对象的引用 //如果没相同的对象就在字符串中创建该对象,然后将该对象的引用返回 String a = "123"; String b = "123"; //== 比较的是内存地址是否相等 if(a == b){ System.out.println("输出相等"); }