Java中的String是不可变对象

在面向对象及函数编程语言中,不可变对象(英语:Immutable object)是一种对象,在被创造之后,它的状态就不可以被改变。至于状态可以被改变的对象,则被称为可变对象(英语:mutable object)。-- 来自百度百科

Java8 String源码

public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];//Java 9已经优化为byte数组了 /** Cache the hash code for the string */
private int hash; // Default to 0 ...
}

显然String字符串内部是使用char[]数组来存储。

而这个char[]数组是用 private final来修饰的,private就体现着面向对象的封装特性,并且String没有提供供外部访问的方法,这就意味着这个属性无法被外部访问;final则意味着这个属性无法修改,无法重新指向其他对象。且String 类没有提供/暴露修改这个字符串的方法。

因此,String是不可变对象

不可变的优点

  • 线程安全。同一个字符串实例可以被多个线程共享,因为字符串不可变,本身就是线程安全的。
  • 支持hash映射。因为String的hash值经常会使用到,比如作为 Map 的键,不可变的特性也就使得hash值不会变,不需要重新计算。
  • 字符串常量池优化。String对象创建之后,会缓存到字符串常量池中,下次需要创建同样的对象时,可以直接返回缓存的引用。

一定不可变吗

事实上,可以通过反射来改变String中的值

String str = "abcdef";
System.out.println("修改前的地址值:" + str + ",hash值"+ str.hashCode());
Class<? extends String> aClass = str.getClass();
Field value = aClass.getDeclaredField("value");
value.setAccessible(true);
value.set(str,"seven".getBytes());
System.out.println("修改后的地址值:" + str + ",hash值"+ str.hashCode());

显然修改后的还是同一个地址和hash值

修改前的地址值:abcdef,hash值-1424385949
修改后的地址值:seven,hash值-1424385949

查看源码可以看到,计算hashcode后hash值是由一个常量缓存下来的,所以通过反射修改后hashCode并不会变,除非进行重新计算。

注意:用反射修改String的值破坏了String的immutable特征,可能会带来各种问题,以上只是提供一个思路,不建议这么做。

不可变类都建议参考String类一样,写个变量缓存hashcode,从而防止高并发下的计算

public int hashCode() {
int h = hash;
if (h == 0 && !hashIsZero) {
h = isLatin1() ? StringLatin1.hashCode(value)
: StringUTF16.hashCode(value);
if (h == 0) {
hashIsZero = true;
} else {
hash = h;
}
}
return h;
}

关于作者

来自一线程序员Seven的探索与实践,持续学习迭代中~

本文已收录于我的个人博客:https://www.seven97.top

公众号:seven97,欢迎关注~

String真的不可变吗?的更多相关文章

  1. 在Java中String类为什么要设计成final?String真的不可变吗?其他基本类型的包装类也是不可变的吗?

    最近突然被问到String为什么被设计为不可变,当时有点懵,这个问题一直像bug一样存在,竟然没有发现,没有思考到,在此总结一下. 1.String的不可变String类被final修饰,是不可继承和 ...

  2. Java 中的 String 真的是不可变吗?

    我们都知道 Java 中的 String 类的设计是不可变的,来看下 String 类的源码. public final class String implements java.io.Seriali ...

  3. String 的不可变真的是因为 final 吗?

    尽人事,听天命.博主东南大学硕士在读,热爱健身和篮球,乐于分享技术相关的所见所得,关注公众号 @ 飞天小牛肉,第一时间获取文章更新,成长的路上我们一起进步 本文已收录于 「CS-Wiki」Gitee ...

  4. Java中的String类真的不可变吗?java面试常见问题

      其实在Java中,String类被final修饰,主要是为了保证字符串的不可变性,进而保证了它的安全性.那么final到底是怎么保证字符串安全性的呢?接下来就让我们一起来看看吧. 一. final ...

  5. Java基础知识强化101:Java 中的 String对象真的不可变吗 ?

    1. 什么是不可变对象?       众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对 ...

  6. 为什么String被设计为不可变?是否真的不可变?

    1 对象不可变定义 不可变对象是指对象的状态在被初始化以后,在整个对象的生命周期内,不可改变. 2 如何不可变 通常情况下,在java中通过以下步骤实现不可变 对于属性不提供设值方法 所有的属性定义为 ...

  7. String真的是不可变的吗?

    你可能问一个人String是可变的吗?想必他们都会一口同生的说String是不可变的,因为String是final修饰的,而且它底层的是final修饰的char[]数组. 可以看到String源码: ...

  8. String为什么不可变

    转载:http://www.importnew.com/7440.html https://www.cnblogs.com/leskang/p/6110631.html 什么是不可变对象? 众所周知, ...

  9. 从字节码和JVM的角度解析Java核心类String的不可变特性

    1. 前言 最近看到几个有趣的关于Java核心类String的问题. String类是如何实现其不可变的特性的,设计成不可变的好处在哪里. 为什么不推荐使用+号的方式去形成新的字符串,推荐使用Stri ...

  10. 知识点:tuple 元素真的不可变吗

    tuple 元素真的不可变吗 有一种有序列表叫元组:tuple. tuple和list非常类似,但是tuple一旦初始化就不能修改,比如同样是列出单位或同学的名字: >>> clas ...

随机推荐

  1. 在centos开启防火墙没启动22/tcp or 22/udp的情况下是如何ssh连上的

    偶尔间查询防火墙的22/tcp or 22/udp ,看到是no的状态,而且此时也是ssh登陆的,然后就反复尝试,关闭22端口,开启,重载,重启.甚至连上另个服务器发现还是一样的情况.在群里问大佬们终 ...

  2. 震撼登场,全国产RK3588J工业核心板,让您的产品更具特色!八核2.4GHz!

    RK3588J全国产工业核心板10月正式出售如需预定,请与创龙科技联系. 更多详情,请登录创龙科技天猫旗舰店. 瑞芯微RK3568J.RK3588J技术交流QQ群:567208221,欢迎加入!

  3. 移动web布局方法

    继续更新移动端的一个布局,这也是经典中的经典,当初只知道个rem和vwvh适配,其实这里面还有很多的门道不只是一个适配这么简单 一.前置 1.背景缩放 我们都知道做移动端,给的图都是二倍图,你拿来用直 ...

  4. python3 模型日记

    说明 作为一种 python 框架模型的记录吧,用于个人总结,不定时更新. 正文 1. 主进程退出后,子进程也跟着退出 之前遇到过一种情况,用 flet 写了一个页面,然后又同时开了一个 tcp se ...

  5. VulnHub_DC-3渗透流程

    VulnHub_DC-3 DC-3 是另一个特意建造的易受攻击的实验室,旨在获得渗透测试领域的经验. 与之前的 DC 版本一样,这个版本是为初学者设计的,尽管这一次只有一个flag.一个入口点并且根本 ...

  6. Spring的xml和注解对比

    常用注解 bean定义 XML方式:<bean></bean> 注解方式:@Component 通用组件 @Controller(web层) @Service(service层 ...

  7. win10打不出中文的修复方法!

    说明 在Win10系统中,默认自带了中文输入法,使用起来非常的方便,但有时win10系统中自带的输入法会打不出中文的情况,该怎么办呢?遇到这样的问题,我们可以参考下本文中的方法来修复. 步骤: cmd ...

  8. Git 清除缓存账密

    [已解决] git push 报错:git: 'credential-manager' is not a git command. See 'git --help'. 解决方案1)运行 git con ...

  9. vue 理解yarn start 和yarn dev的区别

    yarn dev,当文件变动后,会自动重启. yanr start不会自动重启 nodemon会监听文件变动,跟yarn dev和yarn start无关.

  10. Java 监听POST请求

    要监听POST请求,我们可以使用Java中的HttpServlet类.以下是一个使用Servlet API监听POST请求的完整示例.这个示例使用了Servlet 3.1规范,不需要在web.xml中 ...