为什么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内置的一些类型中 可变对象: ...
随机推荐
- 设计模式之Factory模式 代码初见
ObjectFactory就是通过Factory建造一个Object,比如说DBConnectionFactory就是专门建造DBConnection的工厂 BuilderFactory就是通过Fac ...
- (一)MYSQL ERROR 2003 (HY000): Can't connect to MySQL server on '192.168.10.210' (111) 解决方法
今天在测试MySQL的连接时候,发现连接不通过,并报错ERROR 2003 (HY000): Can't connect to mysql server on '192.168.10.210' (11 ...
- Asp.Net MVC 读取json文件
有些系统上面的配置可以做成config里面的appsetting.这里要求写在json文件里面. 首先 添加命名空间 using Newtonsoft.Json; using System.IO; u ...
- js获取文件后缀
//获取文件后缀 function getType(file){ var filename=file; var index1=filename.lastIndexOf("."); ...
- 统计字符串中字符出现的次数(||和&&的区别)
var str = "ProsperLee"; // || 返回第一个为真的表达式的值,若全为假则返回最后一个表达式的值 // && 返回第一个为假的表达式的值,若 ...
- postman测试方法,出现400错误码
下午毛概课上帮同学debug了个错误: postman测试 ,得到返回 400的状态码错误: 查询博客: https://blog.csdn.net/zhangmengleiblog/article/ ...
- web.xml设置过滤直接访问
<security-constraint> <web-resource-collection> <web-resource-name>JSPs</web-re ...
- C#字符串转二进制、二进制转字符串
最近公司要做一个操作日志的模块,如果将操作日志以字符串的形式存到后台数据库,非常浪费内存,不可取,特意写了字符串与二进制相互转换的函数. 1.字符串转二进制 private string String ...
- 【原】Java学习笔记015 - 面向对象
package cn.temptation; public class Sample01 { public static void main(String[] args) { // 传递 值类型参数 ...
- 基于 PHP 的数据爬取(QueryList)
基于PHP的数据爬取 官方网站站点 简单. 灵活.强大的PHP采集工具,让采集更简单一点. 简介: QueryList使用jQuery选择器来做采集,让你告别复杂的正则表达式:QueryList具有j ...