JAVA基础5——与String相关的系列(1)
与String相关的系列
String, 是JAVA中常见的一个引用类型,且其具有一定的特殊性。
String类型被设置为final型,即不可继承,也就不可修改其中的实现。
String可以改变吗
String被设置为final型的,通常情况下是不可以改变的。
但是,从源码中可以得知,其字符串存储的时候使用的是char[],虽然被标识为final型,但是可以通过反射等方式修改其中的值,但是不推荐。
反射 修改字符串实际值的步骤 :
- 获反射获取到数组对应的字段Field
- 修改器访问属性为可访问
- 修改其中的数组中的值。
详细可以参考下http://www.cnblogs.com/fguozhu/articles/2661055.html,讲解的非常详细。
关于JAVA虚拟机中的字符串常量池
在JAVA虚拟机(JVM)中存在着一个字符串池,其中保存着很多String对象,并且可以被共享使用,因此它提高了效率。由于String类是final的,它的值一经创建就不可改变,因此我们不用担心String对象共享而带来程序的混乱。字符串池由String类维护,我们可以调用intern()方法来访问字符串池。
以String s = "abc"为例,这行代码被执行的时候,JAVA虚拟机首先在字符串池中查找是否已经存在了值为"abc"的这么一个对象,它的判断依据是String类equals(Object obj)方法的返回值。如果有,则不再创建新的对象,直接返回已存在对象的引用;如果没有,则先创建这个对象,然后把它加入到字符串池中,再将它的引用返回。
对于字符串是否会进入常量池中:
- 如果是使用字面量的方式(即双引号定义字符串)定义字符串,JVM执行时会首先去常量池中查找是否已经存在,如果存在就直接返回,如果不存在就在常量池中创建,并返回引用。
- 如果是使用new String()的方式创建字符串,则必须手动调用intern()方法,才会去执行将内容放入常量池的操作(这个JDK6、7、8有着不同的实现逻辑,后面详细介绍。)
常量池的内存模型介绍
关于详细介绍,看下下面几个介绍,讲解的非常详细,也很透彻:
http://www.jianshu.com/p/4ee6aec39c89?from=groupmessage
http://blog.csdn.net/zhushuai1221/article/details/52663818
http://blog.csdn.net/baidu_31657889/article/details/52315902
要点阐述如下:
- JDK6版本, 常量池放在Perm方法区,与Heap区完全独立。
- JDK7或者JDK8版本,常量池位于Heap区。
字符串创建与存储机制
- 对于String s = "aaa" 直接双引号的方式:
这种情况下, 首先会到常量池中查找下是否已经存在相同内容的字符串,如果有的话,则直接将变量s指向常量池中已经存在的字符串上面。
- 对于String s = new String("xxx")的方式:
这种情况下, 首先会判断下倡廉吃中是否有相同值得字符串,如有,则拷贝一份到Heap中,然后返回heap中的地址;如果常量池中不存在,则会直接在heap中创建一份,然后将heap地址返回。
此处注意一点,就是如果"xxx"不存在与常量池中的话,也会先在常量池中创建一个(因为参数也是个字符串,下面章节中有讲)。
关于String的intern()方法####
讲完上面的创建存储机制,不得不提及一个不常用的intern()方法。这个方法的作用是,在常量池中查找是否有与当前字符串值相同的常量,如果没有,则新建常量并返回常量引用,但当前引用不变;如果有直接返回引用。intern()方法的设计初衷就是重用String对象,进而可以节省内存消耗。
先看下下面这个代码:
String str1 = new String("SEU")+ new String("Calvin");
System.out.println(str1.intern() == str1);
System.out.println(str1 == "SEUCalvin");
执行结果:
true
true
String str2 = "SEUCalvin";//新加的一行代码,其余不变
String str1 = new String("SEU")+ new String("Calvin");
System.out.println(str1.intern() == str1);
System.out.println(str1 == "SEUCalvin");
执行结果:
false
false
上面两段代码,看似str2与其余的没有任何关系,却影响到了str1的输出结果。这个实际上与intern()方法有关系。
intern()方法在JDK1.6中的作用是:比如String s = new String("SEU_Calvin"),再调用s.intern(),此时返回值还是字符串"SEU_Calvin",表面上看起来好像这个方法没什么用处。但实际上,在JDK1.6中它做了个小动作:检查字符串池里是否存在"SEU_Calvin"这么一个字符串,如果存在,就返回池里的字符串;如果不存在,该方法会把"SEU_Calvin"添加到字符串池中,然后再返回它的引用。
intern()方法在JDK1.7或者1.8版本中的作用是:比如String s3 = new String("1") + newString("1"),此时s3对象对应的内存内容“11”存储在Heap区域,此时常量池中并无字符串11, 执行intern()方法的时候,先去常量池中看下11是否已经存在,如果不存在的话则直接将引用指向Heap中“11”字符串的地址。(这个地方是JDK7以上版本与JDK6的差别所在,即JDK6如果发现常量池中不存在,则会在常量池中创建一份,而JDK7或者JDK8中,如果常量池中没有,则直接将引用指向Heap中已有的字符串对象,而不会重新创建, 因此s3 == s3.intern(),而这个在JDK6中是false的)
JAVA基础5——与String相关的系列(1)的更多相关文章
- JAVA基础5——与String相关的系列(2)
差异点比较 String使用+直接拼接 这种情况需要分两种情况来讨论: 1. 都是确定的字符串常量之间进行的+号拼接的时候,由于在编译器就可以确定其具体值了,所以编译器在编译期的时候就会把这些常量拼接 ...
- Java基础笔记之String相关知识
(二)String Sring 被声明为 final ,因此不可被继承. String的不可变性: 看String的定义(java9版本): public final class String imp ...
- Java基础-字符串(String)常用方法
Java基础-字符串(String)常用方法 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.java的API概念 Java的API(API:Application(应用) Pr ...
- java基础学习日志--String、StringBuffer方法案例
package StringDemo; import java.util.Arrays; /* * 常用String.StringBufer类的方法 */ public class Demo1 { p ...
- 【JAVA - 基础】之String存储机制浅析
本文主要解决以下几个问题 String源码解析? String和new String的区别? String通过"+"或concat累加时的对象创建机制? StringBuilder ...
- Java 基础 - 如何理解String不可变
ref: https://www.zhihu.com/question/20618891 第一个答案. 扩展“ Java 基础 - System.arraycopy() 浅拷贝 深拷贝
- JAVA基础--常用类 String,StringBuffer, 基础数据类型包装类, Math类, Enum类
字符串相关类: String, StringBuffer String类为不可变的字符序列 String s1="hello"; String s2="hello&quo ...
- Java基础知识总结--String、StringBuffer、StringBuilder
1.Java String 类 String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法.在Java中,被final修饰的类是不允许被继承的,并且该类中 ...
- Java基础--常用API--日期相关API
一.java.util.Date 1.只用于显示系统时间,其大部分操作由Calendar代替. 格林威治时间(GMT):指的是1970年1月1日0时,不同地区有时间差. 默认输出格式:星期.月.日.时 ...
随机推荐
- WAMPServer配置修改及问题汇总
备忘录 软件版本wampserver2.5-Apache-2.4.9-Mysql-5.6.17-php5.5.12-64b -------------------------------------- ...
- elasticsearch+kibana+metricbeat安装部署方法
elasticsearch+kibana+metricbeat安装部署方法 本文是elasticsearch + kibana + metricbeat,没有涉及到logstash部分.通过beat收 ...
- 用node.js实现ORM的一种思路
ORM是O和R的映射.O代表面向对象,R代表关系型数据库.二者有相似之处同时也各有特色.就是因为这种即是又非的情况,才需要做映射的. 理想情况是,根据关系型数据库(含业务需求)的特点来设计数据库.同时 ...
- JS难点--面向对象(封装)
我觉得js的难点之一就是面向对象编程. 面向对象 它是一种编程思想,它在写法上比面向过程相对来说复杂一些: 以下是我学习中关于面向对象的知识点总结: 1.什么是对象 从广义上说,"一切皆 ...
- SSH整合的详细步骤
SSH整合 新建一个动态web工程-->加入Spring-->加入Hibernate-->加入Struts2 1.在 web中应用Spring 目的:在web应用程序加载成功之后,就 ...
- java8Stream原理深度解析
Java8 Stream原理深度解析 Author:Dorae Date:2017年11月2日19:10:39 转载请注明出处 上一篇文章中简要介绍了Java8的函数式编程,而在Java8中另外一个比 ...
- The Suspects(并查集维护根节点信息)
The Suspects Time Limit: 1000MS Memory Limit: 20000K Total Submissions: 37090 Accepted: 17980 De ...
- Java中方法的重载和重置(覆盖)的区别
简单来说,重载就是在同一类中允许同时存在一个以上的同名方法,只要这些方法的参数个数或类型不同即可,而重置(覆盖)是子类重新定义父类中己经定义的方法,即子类重写父类方法. 方法的重载 方法的重载就是在同 ...
- Hive中常用的查询命令
日志数据的统计处理在这里反倒没有什么特别之处,就是一些 SQL 语句而已,也没有什么高深的技巧,不过还是列举一些语句示例,以示 hive 处理数据的方便之处,并展示 hive 的一些用法. a) ...
- 蓝桥杯-算法训练--ALGO-4 结点选择
本人是一个刚刚接触C++不久的傻学生~记录一些自己的学习过程.大神路过可以批评指正~ 刚学动态规划,水平还很渣,一下子不知道从何下手,借鉴了一下这位大哥的文章 http://www.cnblogs.c ...