• String 对象的不可变性

java8中的String只有2个属性value和hash,相关代码如下:

 /** The value is used for character storage. */
private final char value[]; /** Cache the hash code for the string */
private int hash; // Default to 0

value是字符串的字符数组,hash是字符串的hash值缓存

public final class String
implements java.io.Serializable, Comparable<String>, CharSequence

其中String 类被 final 关键字修饰了,而且变量 char 数组也被 final 修饰了。

我们知道类被 final 修饰代表该类不可继承,而 char[] 被 final+private 修饰,代表了 String 对象不可被更改。Java 实现的这个特性叫作 String 对象的不可变性,即 String 对象一旦创建成功,就不能再对它进行改变。

  • Java 这样做的好处在哪里呢?

第一,保证 String 对象的安全性。假设 String 对象是可变的,那么 String 对象将可能被恶意修改。

第二,保证 hash 属性值不会频繁变更,确保了唯一性,使得类似 HashMap 容器才能实现相应的 key-value 缓存功能。

第三,可以实现字符串常量池。在 Java 中,通常有两种创建字符串对象的方式,一种是通过字符串常量的方式创建,如 String str=“abc”;另一种是字符串变量通过 new 形式的创建,如 String str = new String(“abc”)。

当代码中使用第一种方式创建字符串对象时,JVM 首先会检查该对象是否在字符串常量池中,如果在,就返回该对象引用,否则新的字符串将在常量池中被创建。这种方式可以减少同一个值的字符串对象的重复创建,节约内存。

String str = new String(“abc”) 这种方式,首先在编译类文件时,"abc"常量字符串将会放入到常量结构中,在类加载时,“abc"将会在常量池中创建;其次,在调用 new 时,JVM 命令将会调用 String 的构造函数,同时引用常量池中的"abc” 字符串,在堆内存中创建一个 String 对象;最后,str 将引用 String 对象。

  • 平时对String的误解

平常编程时,对一个 String 对象 str 赋值“hello”,然后又让 str 值为“world”,这个时候 str 的值变成了“world”。那么 str 值确实改变了,为什么我还说 String 对象不可变呢?

在 Java 中要比较两个对象是否相等,往往是用 ==,而要判断两个对象的值是否相等,则需要用 equals 方法来判断。

这是因为 str 只是 String 对象的引用,并不是对象本身。对象在内存中是一块内存地址,str 则是一个指向该内存地址的引用。所以在刚刚我们说的这个例子中,第一次赋值的时候,创建了一个“hello”对象,str 引用指向“hello”地址;第二次赋值的时候,又重新创建了一个对象“world”,str 引用指向了“world”,但“hello”对象依然存在于内存中。也就是说 str 并不是对象,而只是一个对象引用。真正的对象依然还在内存中,没有被改变。

  • String.intern 的原理

首先看下面这段代码及其结果:

在字符串常量中,默认会将对象放入常量池;在字符串变量中,对象是会创建在堆内存中,同时也会在常量池中创建一个字符串对象,复制到堆内存对象中,并返回堆内存对象引用。

如果调用 intern 方法,会去查看字符串常量池中是否有等于该对象的字符串,如果没有,就在常量池中新增该对象,并返回该对象引用;如果有,就返回常量池中的字符串引用。堆内存中原有的对象由于没有引用指向它,将会通过垃圾回收器回收。

使用 intern 方法需要注意的一点是,一定要结合实际场景。因为常量池的实现是类似于一个 HashTable 的实现方式,HashTable 存储的数据越大,遍历的时间复杂度就会增加。如果数据过大,会增加整个字符串常量池的负担。


关于java8中的String的更多相关文章

  1. java8中map的meger方法的使用

    java8中map有一个merge方法使用示例: /** * 打印出包含号码集的label的集合 * * @param args */ public static void main(String[] ...

  2. java8中CAS的增强

    注:ifeve.com的同名文章为本人所发,此文在其基础做了些调整.转载请注明出处! 一.java8中CAS的增强 前些天,我偶然地将之前写的用来测试AtomicInteger和synchronize ...

  3. java8中的map和reduce

    java8中的map和reduce 标签: java8函数式mapreduce 2014-06-19 19:14 10330人阅读 评论(4) 收藏 举报  分类: java(47)  FP(2)  ...

  4. Java8中Lambda表达式的10个例子

    Java8中Lambda表达式的10个例子 例1 用Lambda表达式实现Runnable接口 //Before Java 8: new Thread(new Runnable() { @Overri ...

  5. 初探Java8中的HashMap(转)

    HashMap是我们最常用的集合之一,同时Java8也提升了HashMap的性能.本着学习的原则,在这探讨一下HashMap. 原理 简单讲解下HashMap的原理:HashMap基于Hash算法,我 ...

  6. 谈一谈Java8的函数式编程(二) --Java8中的流

    流与集合    众所周知,日常开发与操作中涉及到集合的操作相当频繁,而java中对于集合的操作又是相当麻烦.这里你可能就有疑问了,我感觉平常开发的时候操作集合时不麻烦呀?那下面我们从一个例子说起. 计 ...

  7. java8中Lambda表达式和Stream API

    一.Lambda表达式 1.语法格式 Lambda是匿名函数,可以传递代码.使用“->”操作符,改操作符将lambda分成两部分: 左侧:指定了 Lambda 表达式需要的所有参数 右侧:指定了 ...

  8. java8中的接口与时间操作

    java8中接口可以有默认方法(用default修饰,可以有多个)和静态方法了. public interface Tran { default public String getName() { r ...

  9. Java8中的 lambda 和Stream API

    前言 ​ 由于项目中用到了比较多有关于 Java8 中新的东西,一开始自己只是会写,但是写起来不太顺,然后就在网上找到了一个很好的关于Java8新特性的视频,所以就进行了学习了一下,以下是自己对 la ...

随机推荐

  1. 模糊查询的sql语句

    Java程序中使用的sql语句一直不明白是什么作用,在网上搜索了一些资料,看到一篇博客,稍微解答了具体每条代码的作用,因为作者加了详细的注解,可以作为参考 <JavaWeb dao层条件查询(模 ...

  2. 第107题:二叉树的层次遍历II

    一. 问题描述 给定一个二叉树,返回其节点值自底向上的层次遍历. (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) 例如: 给定二叉树 [3,9,20,null,null,15,7], 3 ...

  3. 2019HDU多校Path——最短路最小割

    题目 给出一个 $n$ 个顶点 $m$ 条边的图,要求阻塞一些边,使得从 $1$ 到 $n$ 的最短路变长,求阻塞的边长度和的最小值,不必保证阻塞后可达. 分析 很显然,要阻塞的边肯定在最短路图上,先 ...

  4. sql 存储过程记录

    -- exec sp_helptext add_book1 CREATE proc add_book1 --创建存储过程 @DocCode VARCHAR() --创建参数 as BEGIN INSE ...

  5. Material Icons 查找的替代办法

    1 问题 1.1 国内访问 google 困难,众所周知 1.2 在平时的工作中使用 Material Icons 如何查询呢 2 办法 2.1 github.com 把包 download 2.2 ...

  6. luogu 3998 [SHOI2013]发微博 map

    考试的时候被卡常了~ code: #include <bits/stdc++.h> #define ll long long #define N 200002 #define setIO( ...

  7. 查看Oracle表空间使用情况

    1.查询表空间的总容量 as MB from sys.dba_data_files a group by a.TABLESPACE_NAME 2.查询表空间的空闲容量 select b.TABLESP ...

  8. Git生成本机SSH Key并添加到GitHub中

    1.检查电脑里是否有SSH Key 打开git Bash客户端 cd ~/.ssh ls 如果有就会输出下面内容 config id_rsa id_rsa.pub known_hosts 2.创建 邮 ...

  9. Flask 四种响应类型

    1 直接返回字符串 可以返回状态码 @app.route('/testresponse', methods=['GET', 'POST']) def testresponse(): return &q ...

  10. pwn学习日记Day8 基础知识积累

    知识杂项 aslr:是一种针对缓冲区溢出的安全保护技术,通过对堆.栈.共享库映射等线性区布局的随机化,通过增加攻击者预测目的地址的难度,防止攻击者直接定位攻击代码位置,达到阻止溢出攻击的目的的一种技术 ...