分析Java中为什么String不可变
作者:烟花散尽13141 发布时间:2023-06-05 23:33:25
常量池
Java中我们创建String对象有两种基本方法。
String str1 = "zxhtom";
String str2 = new String("zxhtom");
上面两种方式我们创建了两个String变量 。 但是第一种通过双引号创建的zxhtom这个对象我们称之为常量 。 在JVM中是存储在一块叫【常量池】中的。而第二种str2是我们称之为普通变量。new一次就在JVM中开辟一块内存。
【常量池】的作用就是复用,当同样的内容再次被通过常量方式创建的时候Java会指向同一块地址。通过如下代码理解:
String z1 = "zxhtom";
String z2 = "zxhtom";
通过上图我们可以了解 z1 , z2两个变量其实引用的是同一内存地址 。 所以z1==z2 为true .
到这里引发出为什么String被设计为不可变 。 上列中z1 被修改成zxh . 如果String是可变得那么z2就会被莫名其妙修改成zxh .
便利
在Java中判断两个对象相等时通过地址判断。但是地址被抽象话为一段hash函数。在Java使用中hash是经常被使用的。将String设置为不可变性那么hash就可以一直使用下去。不需要重新计算体现了便捷性
安全
仍是上面的情况 , z2会被不知情的情况下被修改了。这在多线程中很常见。我们在使用的时候会被其他情况将数据更改。这样我们的数据将会失去了准确性。
引申问题
在上部中我们提到String的常量池。针对常量池引发思考 【String.intern()】
该方法的功能就是扩充【常量池】。z2.intern() 表示判断常量池中是否存在与该值相同的对象如果有则返回该对象的引用。 如果没有则将该值注册到内存中。注意这里并不是将z2对象注册过去。而是将z2的值注册进去。
String z1=new String("zxhtom");
String z2=z1.intern();
System.out.println( z1==z1.intern() );
System.out.println( z1.hashCode()+" "+z2.hashCode() );
System.out.println( z2==z1 );
System.out.println( z2==z1.intern() );
输出结构
false
-688175064 -688175064
false
true
分析一下输出结果不难发现,z1.intern()是常量池中没有zxhtom,会将zxhtom值创建到常量池中,z2就是引用常量池中的引用。这个时候z1==z2 为false说明注册到常量池中的并不是z1的地址,而是相当于z1的一个对象拷贝。
string创建方式的确定简单归结:
通过双引号创建的 == 常量创建
通过常量拼接 == 常量创建
通过非常量与常量拼接 = 非常量创建
通过new 创建 == 非常量创建
String在Java中的【引用传递】
在Java中方法参数传递都是通过值传递的。但是为什么String给我们的感觉是引用传递的呢?
public static void main(String[] args) {
String x = new String("ab");
change(x);
System.out.println(x);
}
public static void change(String x) {
x = "cd";
}
String不是基本对象所以String是引用传递。但是这里的引用传递知识传递String引用的地址 .当执行x=cd是原来ab的对象还在JVM中。外部x的引用地址没有变 。 变得知识change方法中x的指向。所以外部打印的还是ab
来源:https://www.cnblogs.com/zhangxinhua/p/zxhtom13141.html


猜你喜欢
- 什么是mybatis,mybatis有什么特点,下面先给大家介绍下mybatis的概念及特点。jdbc开发优缺点:1)优点:简单易学,上手快
- 上标是指比同一行中其他文字稍高的文字,而下标是指比同一行中其他文字稍低的文字。在生活中,我们常见的平方米、立方米等符号以及化学中的各种元素符
- 为何使用分布式系统限流:在分布式环境中,我们的系统都是集群化部署,那么使用了单机版的限流策略,比如我们对某一个接口的限流方案是每秒钟最多10
- 近期对两个应用进行改造,在上线过程中出现一系列问题(其中一部分是由于ObjectId误区导致的)先来了解下ObjectId:TimeStam
- 在很多场景下,maven不能直接访问到外网时,使用代理是其中常见的一种方式。这篇文章整理一下常见的maven中设置代理的方法。代理服务器代理
- 概述本篇文章主要讲解下Map家族中3个相对冷门的容器,分别是WeakHashMap、EnumMap、IdentityHashMap, 想必大
- 场景点击第一个Activity中的按钮,启动第二个Activity,关闭第二个Activity,返回到第一个Activity。在第一个Act
- 本文实例为大家分享了java实现人机猜拳游戏的具体代码,供大家参考,具体内容如下完成人机猜拳互动游戏的开发,用户通过控制台输入实现出拳,电脑
- 何时需要削峰当上游调用下游服务速率高于下游服务接口QPS时,那么如果不对调用速率进行控制,那么会发生很多失败请求通过消息队列的削峰方法有两种
- org.slf4j.Logger中info()方法如果info()方法参数为以下类型 public void in
- 前言Emmmm…最近在做项目的途中,有遇到一个方法需要接收的参数只有一个或者较少的时候就懒得写实体类去接收,使用spr
- Spring Boot 的启动原理可以概括为以下几个步骤:加载 Spring Boot 应用程序的启动类根据启动类所在的包路径扫描相关的类根
- 前言我们在日常的开发过程中针对一些字段采用整型的方式去代替某些具体的含义,比如性别0代表男,1代表女。如果只是一些不会变更的转译我们可以采用
- 在Android Studio 3.0中一旦我们创建了一个项目,一个名为mipmap-anydpi-v26自动创建的文件夹在res文件夹下。
- 这篇文章主要介绍了Java方法重载Overload原理及使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值
- 1.Android 连接MySQL数据库public class DBOpenHelper {private static String d
- 一、关键字分类C语言一共多少个关键字呢?一般的书上,都是32个(包括本书),但是这个都是C90(C89)的标准。其实C99后又新增了5个关键
- Android Notification使用详解Notification核心代码(链式调用):适用于Android 4.0以上(
- 一、引用:1.建立一个WinForm工程,默认生成了一个WinForm窗体Form1(此处默认为主窗体)。2.引用—>添加引用—>
- //程序下载升级 zhouxiang@JavascriptInterfacepublic void UpdateCAECP(final St