再解java中的String
今天看到一篇文章中,写了关于java中的String。我看了后,是我从学java来觉得是最好的一篇关于String类的文章。看了这篇文章你就会对String的认识会提高一个层次。故将原作者的文章特意转载过来分享下。
作者: chenssy
今天朋友问我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的更多相关文章
- java中String是对象还是类?详解java中的String
有很多人搞不懂对象和类的定义.比如说java中String到底是对象还是类呢? 有人说String 既可以说是类,也可以说是对象. 其实他这么说也没问题, 类和对象其实都是一个抽象的概念. 我们可以把 ...
- 详解Java中的clone方法
详解Java中的clone方法 参考:http://blog.csdn.net/zhangjg_blog/article/details/18369201/ 所谓的复制对象,首先要分配一个和源对象同样 ...
- 关于JAVA中的String的使用与连接(转)
JAVA中的String连接性能 Java中的String是一个非常特殊的类,使它特殊的一个主要原因是:String是不可变的(immutable). String的不可变性是Ja ...
- 详解Java中的clone方法:原型模式
转:http://developer.51cto.com/art/201506/478985.htm clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象.所谓的 ...
- Java中的String为什么是不可变的?
转载:http://blog.csdn.net/zhangjg_blog/article/details/18319521 什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那 ...
- Java中的String与常量池[转帖]
string是java中的字符串.String类是不可变的,对String类的任何改变,都是返回一个新的String类对象.下面介绍java中的String与常量池. 1. 首先String不属于8种 ...
- Java中的String与常量池
string是java中的字符串.String类是不可变的,对String类的任何改变,都是返回一个新的String类对象.下面介绍java中的String与常量池. 1. 首先String不属于8种 ...
- Java基础知识强化101:Java 中的 String对象真的不可变吗 ?
1. 什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对 ...
- Java中的String,StringBuilder,StringBuffer三者的区别
最近在学习Java的时候,遇到了这样一个问题,就是String,StringBuilder以及StringBuffer这三个类之间有什么区别呢,自己从网上搜索了一些资料,有所了解了之后在这里整理一下, ...
随机推荐
- [Web API] Web API 2 深入系列(2) 消息管道
目录 HttpMessageHandler Web Host模式处理过程 Self Host模式处理过程 HttpMessageHandler Web API处理管道由一系列HttpMessageHa ...
- php页面静态化技术;学习笔记
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 从View向Controller传递复杂类型Json
mvc给我们提供多种controller中读取view数据的方法 1.从Ruquest["name"]中直接读取 2.将表单中name名称直接写在Action的参数列表中 3.将表 ...
- ibatis 和 mybatis
ibatis 在daoImpl 层 继承 SqlMapClientDaoSupport 实现 dao 层的接口. this.getSqlMapClientTemplate().queryForObj ...
- <%@ page contentType="text/html; charset=utf-8" language="java"%>每一个字符的含义
contentType="text/html:网页类型htmlcharset=utf-8"网页编码类型language="java"网页编程语言<% @ ...
- TensorFlow知识总结
学习资料: 英文官方网站 Tensorflow 将要写的博客目录: 1.使用Spring AOP对异常进行统一处理 2.动态代理模式理解 aop中的动态代理模式 3.工厂模式三种的理解.logger ...
- Linux-安装Oracle(CentOS-Oracle 12c)
第一步:网络连接,在我的上一篇博客中有介绍,不再多说. 网络连接的目的:为了能使用yum命令,在网上直接下载文件. 第二步:前往oracle官网下载12c database服务器端的两个文件:(安装在 ...
- CSS3 莲花盛开动画
点击这里查看效果:http://keleyi.com/a/bjad/32gxxsaw.htm 或者:http://keleyi.com/keleyi/phtml/css3/10a.htm 效果图: 代 ...
- 前端Demo常用库文件链接
<!doctype html><html><head> <meta charset="UTF-8"> <title>前端 ...
- 关于jquery中用函数来设置css样式
关于jquery中用函数来设置css样式 2016-12-21 23:27:55 1.jquery语法 $(selector).css(name,function(index,value)) name ...