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时,不同地区有时间差. 默认输出格式:星期.月.日.时 ...
随机推荐
- win10 uwp 活动磁贴
本文翻译:https://mobileprogrammerblog.wordpress.com/2015/12/23/live-tiles-and-notifications-in-universal ...
- 用 Eclipse 创建一个简单的web项目
Eclipse neon 汉化版 ; 1;右击新建 --> 选择 动态Web项目 2: 填写 项目名 项目位置 ; 选择 Dynamic web module version 和 tomca ...
- 一张表搞懂各种 Docker 监控方案 - 每天5分钟玩转 Docker 容器技术(86)
前面我们已经介绍了ps/top/stats.Sysdig.Weave Scope.cAdvisor 和 Prometheus 多种容器监控工具和方案,是时候做一个比较了.下面将从五个方面来对比它们之间 ...
- python 带小数点时间格式化
#获取带小数点的时间>>> import datetime #当前时间加3天 >>> t1 = datetime.datetime.now() + datetime ...
- C++中的endl
从开始接触C++到现在,一直以为语句 cout << "hello world!" << endl; 中的endl只是一个相当于C中的换行'\n':直到今天 ...
- 【初学者必读】能让你月薪过万的5大web前端核心技能
前言Web前端开发所涉及的内容主要包括W3C标准中的结构.行为和表现,那么这三项中我们需要掌握的核心技能是什么呢?看小编来为你揭开谜底的. 1.开发语言 HTML发展历史有二十多年,历经多次版本更新, ...
- CSS基础:基础和语法
**CSS语法** CSS 规则由两个主要的部分构成:选择器,以及一条或多条声明.选择器通常是您需要改变样式的 HTML 元素.```selector {declaration1; declarati ...
- 给资源文件添加指纹(Gulp版)
至于为什么要费尽心思地给文件添加指纹,请参看前端静态资源缓存控制策略.这次要达到的小目标就是生成的资源文件能够被客户端缓存,而在文件内容变化后,能够请求到最新的文件. 需要用到的 gulp 插件是 g ...
- ES6新特新之箭头函数使用细节
<=这个大家都知道是小于等于,那么=>是什么呢?今天我们就来探究一下ES6的新特新-----胖箭头函数. 其他语言的函数定义都是很简洁的,但是为什么javaScript的就那么复杂呢?还必 ...
- Autofac学习之三种生命周期:InstancePerLifetimeScope、SingleInstance、InstancePerDependency
InstancePerLifetimeScope:同一个Lifetime生成的对象是同一个实例 SingleInstance:单例模式,每次调用,都会使用同一个实例化的对象:每次都用同一个对象: In ...