今天看到一篇文章中,写了关于java中的String。我看了后,是我从学java来觉得是最好的一篇关于String类的文章。看了这篇文章你就会对String的认识会提高一个层次。故将原作者的文章特意转载过来分享下。

作者: chenssy

出处: http://cmsblogs.com/?p=863

今天朋友问我String的内容是真的不可变吗?我肯定告诉他是的?因为在我的主观意识里String就是一个不可变的对象。于是他给我发了这段程序:

public class StringTest {
    public static void main(String[] args) throws Exception {
        String a = "chenssy";
        System.out.println("a = " + a);
        Field a_ = String.class.getDeclaredField("value");
        a_.setAccessible(true);
        char[] value=(char[])a_.get(a);
        value[4]='_';   //修改a所指向的值
        System.out.println("a = " + a);
    }
}

看到这个简单的程序,我笑了,你这不是从底层来修改String的值么?从这里来理解String的值肯定是可以改变的啦(我们应该始终相信String的不可变性)!接着他再给我一段程序:

public class StringTest {
    public static void main(String[] args) throws Exception {
        String a = "chenssy";
        String b = "chenssy";
        String c = new String("chenssy");
        System.out.println("--------------修改前值-------------------");
        System.out.println("a = " + a);
        System.out.println("b = " + b);
        System.out.println("c = " + c);
        //修改String的值
        Field a_ = String.class.getDeclaredField("value");
        a_.setAccessible(true);
        char[] value=(char[])a_.get(a);
        value[4]='_';   //修改a所指向的值

        System.out.println("--------------修改后值-------------------");
        System.out.println("a = " + a);
        System.out.println("b = " + b);
        System.out.println("chenssy");
        System.out.println("c = " + c);
    }
}

乍看这程序是异常的简单,无非就是赋值、改值、输出嘛!可能你现在就会毫不犹豫的说太简单了结果就是……。但是!!你的毫不犹豫会害死你,而且你的结果很可能错误。那么运行结果是什么呢?

--------------修改前值-------------------
a = chenssy
b = chenssy
c = chenssy
--------------修改后值-------------------
a = chen_sy
b = chen_sy
chen_sy
c = chen_sy

修改前值很容易理解,但是修改后值呢?是不是有点儿不理解呢?你可能会问:为什么System.out.println(“chenssy”);的结果会是chen_ssy,System.out.println(“c = ” + c);也是chen_ssy呢?

要明白这个其实也比较简单,掌握一个知识点:字符串常量池。

我们知道字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串我们使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。每当我们创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串(这点对理解上面至关重要)。

我们再来理解上面的程序。

String a = “chenssy”;

String b = “chenssy”;

a、b和字面上的chenssy都是指向JVM字符串常量池中的”chenssy”对象,他们指向同一个对象。

String c = new String(“chenssy”);

new关键字一定会产生一个对象chenssy(注意这个chenssy和上面的chenssy不同),同时这个对象是存储在堆中。所以上面应该产生了两个对象:保存在栈中的c和保存堆中chenssy。但是在Java中根本就不存在两个完全一模一样的字符串对象。故堆中的chenssy应该是引用字符串常量池中chenssy。所以c、chenssy、池chenssy的关系应该是:c—>chenssy—>池chenssy。整个关系如下:

通过上面的图我们可以非常清晰的认识他们之间的关系。所以我们修改内存中的值,他变化的是所有。

总结:虽然a、b、c、chenssy是不同的对象,但是从String的内部结构我们是可以理解上面的。String c = new String(“chenssy”);虽然c的内容是创建在堆中,但是他的内部value还是指向JVM常量池的chenssy,它构造chenssy时所用的参数依然是chenssy字符串常量。

为了让各位充分理解常量池,特意准备了如下一个简单的题目:

String a = "chen";
String b = a + new String("ssy");

创建了几个String对象??

原作者给出的答案

应该只有两个或者三个!

对于String a = "chen";如果常量池中存在的话,它是不会产生String对象的,直接饮用常量池中的chen即可。

      对于String b = a + new String("ssy");而言,new String("ssy")一定会产生一个String对象,该对象的value指向常量池中"ssy"vlaue。但是到底有没有ssy呢?这要看常量池中是否存在这个字符串了。如果有的话是不会产生ssy的。没有的话才会产生。

       a + new String("ssy");这里也会产生一个。

       所以答案应该是:2、3、4。这是鄙人拙见!!

再解java中的String的更多相关文章

  1. java中String是对象还是类?详解java中的String

    有很多人搞不懂对象和类的定义.比如说java中String到底是对象还是类呢? 有人说String 既可以说是类,也可以说是对象. 其实他这么说也没问题, 类和对象其实都是一个抽象的概念. 我们可以把 ...

  2. 详解Java中的clone方法

    详解Java中的clone方法 参考:http://blog.csdn.net/zhangjg_blog/article/details/18369201/ 所谓的复制对象,首先要分配一个和源对象同样 ...

  3. 关于JAVA中的String的使用与连接(转)

    JAVA中的String连接性能 Java中的String是一个非常特殊的类,使它特殊的一个主要原因是:String是不可变的(immutable).           String的不可变性是Ja ...

  4. 详解Java中的clone方法:原型模式

    转:http://developer.51cto.com/art/201506/478985.htm clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象.所谓的 ...

  5. Java中的String为什么是不可变的?

    转载:http://blog.csdn.net/zhangjg_blog/article/details/18319521 什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那 ...

  6. Java中的String与常量池[转帖]

    string是java中的字符串.String类是不可变的,对String类的任何改变,都是返回一个新的String类对象.下面介绍java中的String与常量池. 1. 首先String不属于8种 ...

  7. Java中的String与常量池

    string是java中的字符串.String类是不可变的,对String类的任何改变,都是返回一个新的String类对象.下面介绍java中的String与常量池. 1. 首先String不属于8种 ...

  8. Java基础知识强化101:Java 中的 String对象真的不可变吗 ?

    1. 什么是不可变对象?       众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对 ...

  9. Java中的String,StringBuilder,StringBuffer三者的区别

    最近在学习Java的时候,遇到了这样一个问题,就是String,StringBuilder以及StringBuffer这三个类之间有什么区别呢,自己从网上搜索了一些资料,有所了解了之后在这里整理一下, ...

随机推荐

  1. Sql Server函数全解(三)数据类型转换函数和文本图像函数

    一:数据类型转换函数 在同时处理不同数据类型的值时,SQL Server一般会自动进行隐士类型转换.对于数据类型相近的值是有效的,比如int和float,但是对于其它数据类型,例如整型和字符类型,隐士 ...

  2. 分享一个UI与业务逻辑分层的框架(三)

    序言 前两篇讲解了UIMediator框架的使用及具体原理代码.本篇讲述MediatorManager的实现代码及展望. MediatorManager MediatorManager的作用有两点: ...

  3. Autofac - 程序集扫描

    通过程序集扫描, 能够自动注册符合规则的类型. 这种方式, 很方便. 这一篇就介绍下程序集扫描吧. 一.扫描 其实前面已经介绍过, 这种方式. 不过并不全. 先看一个之前的方式: var builde ...

  4. 【处理手记】VS2010SP1安装不上Visual Studio 2010 SP1 SDK的解决办法

    想写个VS插件,需要安装VS的SDK,VS2010SP1对应的SDK自然是Visual Studio 2010 SP1 SDK,下载页面: https://www.microsoft.com/en-u ...

  5. 谈一谈.net析构函数对垃圾回收的影响

    之前忘了说了 代码都是在Release模式下运行的,现在补充上. 这里说析构函数,其实并不准确,应该叫Finalize函数,Finalize函数形式上和c++的析构函数很像 ,都是(~ClassNam ...

  6. SharePoint中新创建的Web Application在浏览器中报404错误

    问题描述:在安装完成SharePoint 2010后,进入Central Administration,创建一个新的Web Application,可以正常创建,但访问时却返回404. 平台环境:Wi ...

  7. Java基本概念(1)什么是Java

    什么是Java Java是一种开发语言(核心特点:跨平台,面向对象,名称由来看这里:J2EE里面的2是什么意思),对于开发者来讲,Java基本等于Jdk. Jdk的版本介绍看这里:Java都有那些版本 ...

  8. [moka同学收藏]Vim升华之树形目录插件NERDTree安装图解

    无意中看到实验室的朋友使用的vim竟然能在左边显示树形目录,感觉很方便,这样子文件夹有什么文件一目了然.她说是一个插件叫NERDTree,安装执行后的效果如下,不是你想要的效果就别安了.我的系统是Ub ...

  9. C程序范例(2)——学生管理系统”链表“实现

    1.对于学生管理系统,能够实现的方法有许多,但是今天我们用链表的方法来实现.虽然初学者很可能看不懂,但是不要紧,这是要在整体的系统的学习完C语言之后,我才编写出的程序.所以大家不必要担心.在这里与大家 ...

  10. java实现双链表(差点没写吐系列...)

    刚才把单链表写完了,现在又把双链表写了,双链表和单链表的区别就是每个节点有prior和next两个指针,不同于单链表的一个next指针,而且,正是因为有这两个指针,所以双链表可以前后两个方向去移动指针 ...