为什么String被设计为不可变?是否真的不可变?
1 对象不可变定义
不可变对象是指对象的状态在被初始化以后,在整个对象的生命周期内,不可改变。
2 如何不可变
通常情况下,在java中通过以下步骤实现不可变
- 对于属性不提供设值方法
- 所有的属性定义为private final
- 类声明为final不允许继承
- Return deep cloned objects with copied content for all mutable fields in class
注意:不用final关键字也可以实现对象不可变,使用final只是显示的声明,提示开发者和编译器为不可变。
3 Java中典型的不可变类为String类
为什么String被设计为不可变?
- 安全首要原因是安全,不仅仅体现在你的应用中,而且在JDK中,Java的类装载机制通过传递的参数(通常是类名)加载类,这些类名在类路径下,想象一下,假设String是可变的,一些人通过自定义类装载机制分分钟黑掉应用。如果没有了安全,Java不会走到今天
- 性能 string不可变的设计出于性能考虑,当然背后的原理是string pool,当然string pool不可能使string类不可变,不可变的string更好的提高性能。
- 线程安全 当多线程访问时,不可变对象是线程安全的,不需要什么高深的逻辑解释,如果对象不可变,线程也不能改变它。
4 为什么String是不可变
区分对象和对象的引用
String s = "ABCabc";
System.out.println("s = " + s); s = "123456";
System.out.println("s = " + s);
输出结果:
为什么String对象是不可变的?
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
{
/** The value is used for character storage. */
private final char value[]; /** The offset is the first index of the storage that is used. */
private final int offset; /** The count is the number of characters in the String. */
private final int count; /** Cache the hash code for the string */
private int hash; // Default to 0
在JDK1.7中,String类做了一些改动,主要是改变了substring方法执行时的行为,这和本文的主题不相关。JDK1.7中String类的主要成员变量就剩下了两个:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[]; /** Cache the hash code for the string */
private int hash; // Default to 0
由以上的代码可以看出, 在Java中String类其实就是对字符数组的封装。JDK6中, value是String封装的数组,offset是String在这个value数组中的起始位置,count是String所占的字符的个数。在JDK7中,只有一个value变量,也就是value中的所有字符都是属于String这个对象的。这个改变不影响本文的讨论。 除此之外还有一个hash成员变量,是该String对象的哈希值的缓存,这个成员变量也和本文的讨论无关。在Java中,数组也是对象。 所以value也只是一个引用,它指向一个真正的数组对象。其实执行了String s = “ABCabc”; 这句代码之后,真正的内存布局应该是这样的:
String a = "ABCabc";
System.out.println("a = " + a);
a = a.replace('A', 'a');
System.out.println("a = " + a);
输出结果:
String ss = "123456"; System.out.println("ss = " + ss); ss.replace('1', '0'); System.out.println("ss = " + ss);
ss = 123456
String对象真的不可变吗?
public static void testReflection() throws Exception { //创建字符串"Hello World", 并赋给引用s
String s = "Hello World"; System.out.println("s = " + s); //Hello World //获取String类中的value字段
Field valueFieldOfString = String.class.getDeclaredField("value"); //改变value属性的访问权限
valueFieldOfString.setAccessible(true); //获取s对象上的value属性的值
char[] value = (char[]) valueFieldOfString.get(s); //改变value所引用的数组中的第5个字符
value[5] = '_'; System.out.println("s = " + s); //Hello_World
}
s = Hello_World
为什么String被设计为不可变?是否真的不可变?的更多相关文章
- String的内存模型,为什么String被设计成不可变的
String是Java中最常用的类,是不可变的(Immutable), 那么String是如何实现Immutable呢,String为什么要设计成不可变呢? 前言 关于String,收集一波基础,来源 ...
- 在Java中String类为什么要设计成final?String真的不可变吗?其他基本类型的包装类也是不可变的吗?
最近突然被问到String为什么被设计为不可变,当时有点懵,这个问题一直像bug一样存在,竟然没有发现,没有思考到,在此总结一下. 1.String的不可变String类被final修饰,是不可继承和 ...
- 为什么Java中的String是设计成不可变的?(Why String is immutable in java)
There are many reasons due to the string class has been made immutable in Java. These reasons in vie ...
- Java基础知识强化101:Java 中的 String对象真的不可变吗 ?
1. 什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对 ...
- JAVA的可变类与不可变类
转自: http://www.blogjava.net/hilor/articles/150610.html 可变类和不可变类(Mutable and Immutable Objects)的初步定义: ...
- 【转】Java的可变类与不可变类
1.可变类和不可变类(Mutable and Immutable Objects)的初步定义: 可变类:当你获得这个类的一个实例引用时,你可以改变这个实例的内容. 不可变类:当你获得这个类的一个实例引 ...
- 【Python】可变对象和不可变对象
Python在heap中分配的对象分成两类:可变对象和不可变对象.所谓可变对象是指,对象的内容是可变的,例如list.而不可变的对象则相反,表示其内容不可变. 不可变对象:int,string,flo ...
- Python 可变对象和不可变对象
具体可以看这里:http://thomaschen2011.iteye.com/blog/1441254 不可变对象:int,string,float,tuple 可变对象 :list,dicti ...
- Python入门之python可变对象与不可变对象
本文分为如下几个部分 概念 地址问题 作为函数参数 可变参数在类中使用 函数默认参数 类的实现上的差异 概念 可变对象与不可变对象的区别在于对象本身是否可变. python内置的一些类型中 可变对象: ...
随机推荐
- Spring Cloud Alibaba Nacos 入门
概览 阿里巴巴在2018年7月份发布Nacos, Nacos是一个更易于构建云原生应用的动态服务发现.配置管理和服务管理平台.并表示在6-8个月完成到生产可用的0.8版本,目前版本是0.9版本. Na ...
- php 关于经纬度距离计算方法
1.PHP实现通过经纬度计算距离 单位为公里 function getdistance($lng1,$lat1,$lng2,$lat2)//根据经纬度计算距离 { //将角度转为狐度 $radLat ...
- 一文搞懂TCP与UDP的区别
摘要:计算机网络基础 引言 网络协议是每个前端工程师都必须要掌握的知识,TCP/IP 中有两个具有代表性的传输层协议,分别是 TCP 和 UDP,本文将介绍下这两者以及它们之间的区别. 一.TCP/I ...
- 20190328-CSS样式一:字体样式font-、文本样式text-、背景图样式background-
目录 CSS参考手册:http://css.doyoe.com/ 1.字体简写:font:font-style || font-variant || font-weight || font-size ...
- 从.Net到Java学习第九篇——SpringBoot下Thymeleaf
从.Net到Java学习系列目录 Thymeleaf概述 Thymeleaf 是一个流行的模板引擎,该模板引擎采用java语言开发.模板引擎是一个技术名称,是跨领域平台的概念,在java语言体系下有模 ...
- C/C++ -- 插入排序算法
索引: 目录索引 参看代码 GitHub: Sort.cpp 代码简要分析说明: 1.for(int i=1;i<nSize;i++) 这个外层的for循环, [0][1],[1][2],[2] ...
- Python高级应用(3)—— 为你的项目添加验证码
验证码简介 验证码的作用: 验证码在现在来说,是很常见的东西,可以一定程度的保护网站,比如防止网络爬虫恶意爬取网站数据啊,减少低级的攻击啊什么的.但是高级点的骚操作还是不太好防范,所以现在的验证码平台 ...
- python3操作MySQL数据库,一次插入多条记录的方法
这里提供一个思路,使用字符串拼接的方法,将sql语句拼接出来,然后去执行: l = ["] s = '-' print(s.join(l))
- wxPython树控件
1.树控件 树(tree)是一种通过层次结构展示信息的控件,如下图所示是树控件示例,左窗口中是树控件,在wxPython中树控件类是wx.TreeCtrl. wx.TreeCtrl中一个常用的方法有: ...
- 闭包函数&回调函数
闭包函数&回调函数 谈到回调函数,不得不提匿名函数;匿名函数,也叫闭包函数,也就是没有名字的函数,它可以单独存在,也可以将其赋值给某一个变量.so,先来看一下闭包函数. 闭包函数 php文档: ...