与String相关的系列

String, 是JAVA中常见的一个引用类型,且其具有一定的特殊性。

String类型被设置为final型,即不可继承,也就不可修改其中的实现。

String可以改变吗

String被设置为final型的,通常情况下是不可以改变的。

但是,从源码中可以得知,其字符串存储的时候使用的是char[],虽然被标识为final型,但是可以通过反射等方式修改其中的值,但是不推荐。

反射 修改字符串实际值的步骤 :

  1. 获反射获取到数组对应的字段Field
  2. 修改器访问属性为可访问
  3. 修改其中的数组中的值。

详细可以参考下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)方法的返回值。如果有,则不再创建新的对象,直接返回已存在对象的引用;如果没有,则先创建这个对象,然后把它加入到字符串池中,再将它的引用返回

对于字符串是否会进入常量池中:

  1. 如果是使用字面量的方式(即双引号定义字符串)定义字符串,JVM执行时会首先去常量池中查找是否已经存在,如果存在就直接返回,如果不存在就在常量池中创建,并返回引用。
  2. 如果是使用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

要点阐述如下:

  1. JDK6版本, 常量池放在Perm方法区,与Heap区完全独立。
  2. JDK7或者JDK8版本,常量池位于Heap区。

字符串创建与存储机制

  1. 对于String s = "aaa" 直接双引号的方式:

这种情况下, 首先会到常量池中查找下是否已经存在相同内容的字符串,如果有的话,则直接将变量s指向常量池中已经存在的字符串上面。

  1. 对于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)的更多相关文章

  1. JAVA基础5——与String相关的系列(2)

    差异点比较 String使用+直接拼接 这种情况需要分两种情况来讨论: 1. 都是确定的字符串常量之间进行的+号拼接的时候,由于在编译器就可以确定其具体值了,所以编译器在编译期的时候就会把这些常量拼接 ...

  2. Java基础笔记之String相关知识

    (二)String Sring 被声明为 final ,因此不可被继承. String的不可变性: 看String的定义(java9版本): public final class String imp ...

  3. Java基础-字符串(String)常用方法

    Java基础-字符串(String)常用方法 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.java的API概念 Java的API(API:Application(应用) Pr ...

  4. java基础学习日志--String、StringBuffer方法案例

    package StringDemo; import java.util.Arrays; /* * 常用String.StringBufer类的方法 */ public class Demo1 { p ...

  5. 【JAVA - 基础】之String存储机制浅析

    本文主要解决以下几个问题 String源码解析? String和new String的区别? String通过"+"或concat累加时的对象创建机制? StringBuilder ...

  6. Java 基础 - 如何理解String不可变

    ref: https://www.zhihu.com/question/20618891 第一个答案. 扩展“ Java 基础 - System.arraycopy() 浅拷贝 深拷贝

  7. JAVA基础--常用类 String,StringBuffer, 基础数据类型包装类, Math类, Enum类

    字符串相关类: String, StringBuffer String类为不可变的字符序列 String s1="hello"; String s2="hello&quo ...

  8. Java基础知识总结--String、StringBuffer、StringBuilder

    1.Java String 类 String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法.在Java中,被final修饰的类是不允许被继承的,并且该类中 ...

  9. Java基础--常用API--日期相关API

    一.java.util.Date 1.只用于显示系统时间,其大部分操作由Calendar代替. 格林威治时间(GMT):指的是1970年1月1日0时,不同地区有时间差. 默认输出格式:星期.月.日.时 ...

随机推荐

  1. 前端(各种demo):右侧导航栏的折叠和打开(不使用js)基础版和升级版

    1.给div设置定位. 复习一下—— css中position有五种属性: static:默认值,没有定位 absolute:绝对定位,相对于父级元素进行定位 relative:相对定位 fixed: ...

  2. Android———最详细的系统对话框使用

    在实际应用开发中,用到系统对话框中的情况几乎是没有的.按开发流程来说,UI工程师都会给出每一个弹窗的样式,故而在实际开发中都是自定义弹窗的. 即使用到的地方不多,但是我们也是需要了解并且能熟练的运用它 ...

  3. 常用Linux操作命令

    查看物理CPU个数:cat /proc/cpuinfo| grep "physical id"| sort| uniq| wc -l 查看每个物理CPU中的核数:cat /proc ...

  4. AOP的实现的几种方式

    1.静态代理,实现代码如下,实际上是对装饰器模式的一种应用 interface UserManager { public void addUser(); } class UserManagerImpl ...

  5. Loadrunner Http接口Get/Post方法性能测试脚本解析

    最近使用LoadRunner 11进行了一次完整的Http WEB接口性能测试,下面介绍下Http接口Get/Post方法性能测试脚本通用编写方法. 1. Http接口性能测试基本流程 首先定义了一个 ...

  6. Windows中 MySQL5.7.17解压版安装步骤

    1.先去MySQL官网下载.当前最新版是5.7.19,可能安装方法不同了,本人测试没有安装成功,若有安装成功的朋友,希望分享一下安装步骤. 个人推荐下载MySQL5.7.17,官方下载网址:https ...

  7. LeetCode 563. Binary Tree Tilt (二叉树的倾斜度)

    Given a binary tree, return the tilt of the whole tree. The tilt of a tree node is defined as the ab ...

  8. N厂劳力士黑水鬼V7出了1年,如今依旧被追捧,供不应求

    今天和大家一起来谈谈,风靡复刻界的潜航者,国人眼中的一劳永逸,何为一劳永逸,即(用这个腕表能省很多事)真的有这么牛?其实不然只要是机械腕表都会有或多或少的问题,一劳永逸更多的是指腕表的质量给力,所谓潜 ...

  9. 找到python官方标准库文档

    python中有很多标准库.我们没法记住全部标准库,但是可以在:https://docs.python.org/3/py-modindex.html 中查看标准库的索引 在python的官方文档中,如 ...

  10. thinkphp3.2开发网页实现第三方登录

    1.在要添加登录的html里添加登录按钮: <a href="{:U('Public/login/',array('type'=>'weixin'))}">< ...