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时,不同地区有时间差. 默认输出格式:星期.月.日.时 ...
随机推荐
- Java设计模式(四)——再谈观察者模式
在本系列的上一篇文章中,我们讨论了JDK对于观察者模式的一套实现.今天我们将要从另一个角度来探索Tomcat中是如何利用观察者模式加载各个组件.不过今天的任务不是解释Tomcat,所以我会单独把重点抽 ...
- hover与click样式冲突
如果你的hover事件和click事件的样式不同,如元素背景本来是#fff,如果hover时背景是#ddd,点击时背景是#aaa,那么问题是当你点击后,鼠标再移动到这个元素时背景会变成#ddd,而你希 ...
- PyCharm 2017 免费 破解 注册 激活 教程(附 License Server 地址)(Python 编辑器 IDE 推荐)
许多朋友都在问如何破解 PyCharm 2017 Professional 专业版,咪博士对此是坚决反对的! 不到万不得已,请不要这样做.破解之前,请拖到文章末尾,思考几个问题,想明白你确实需要这样做 ...
- 100. Same Tree(leetcode)
Given two binary trees, write a function to check if they are equal or not. Two binary trees are con ...
- C#基本功之泛型
一.没有泛型之前 在没有泛型之前,我们是怎么处理不同类型的相同操作的: 示例1 //下面是一个处理string类型的集合类型 public class MyStringList { string[] ...
- celery rabbit mq 详解
Celery介绍和基本使用 Celery 是一个 基于python开发的分布式异步消息任务队列,通过它可以轻松的实现任务的异步处理, 如果你的业务场景中需要用到异步任务,就可以考虑使用celery, ...
- python 带小数点时间格式化
#获取带小数点的时间>>> import datetime #当前时间加3天 >>> t1 = datetime.datetime.now() + datetime ...
- 使用python实现计算器功能
学习python过程中的作业.实现了+.-.×./.及幂运算,支持括号优先级. 代码为python3.5 import re def formatEquation(string): string = ...
- xml读取一行数据
#include<map>#include<iostream>#include<fstream>#include<string>using namesp ...
- Ionic3 组件懒加载
使用懒加载能够减少程序启动时间,减少打包后的体积,而且可以很方便的使用路由的功能. 使用懒加载: 右侧红色区域可以省略掉(引用.声明也删掉) 若使用ionic命令新建page,则无需进行下面的操作,否 ...