分析Java中为什么String不可变

常量池

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

以上就是分析Java中为什么String不可变的详细内容,更多关于Java中为什么String不可变的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java String不可变性实现原理解析

    一.原理 1.不变模式(不可变对象) 在并行软件开发过程中,同步操作似乎是必不可少的.当多线程对同一个对象进行读写操作时,为了保证对象数据的一致性和正确性,有必要对对象进行同步.而同步操作对系统性能是相当的损耗.为了能尽可能的去除这些同步操作,提高并行程序性能,可以使用一种不可改变的对象,依靠对象的不变性,可以确保其在没有同步操作的多线程环境中依然始终保持内部状态的一致性和正确性.这就是不变模式. 不变模式天生就是多线程友好的,它的核心思想是,一个对象一旦被创建,则它的内部状态将永远不会发生改变

  • Java 中的 String对象为什么是不可变的

    什么是不可变对象? String对象是不可变的,但这仅意味着你无法通过调用它的公有方法来改变它的值. 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的.不能改变状态的意思是,不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,引用类型指向的对象的状态也不能改变. 区分对象和对象的引用 对于Java初学者, 对于String是不可变对

  • 通过实例解析java String不可变性

    一.原理 1.不变模式(不可变对象) 在并行软件开发过程中,同步操作似乎是必不可少的.当多线程对同一个对象进行读写操作时,为了保证对象数据的一致性和正确性,有必要对对象进行同步.而同步操作对系统性能是相当的损耗.为了能尽可能的去除这些同步操作,提高并行程序性能,可以使用一种不可改变的对象,依靠对象的不变性,可以确保其在没有同步操作的多线程环境中依然始终保持内部状态的一致性和正确性.这就是不变模式. 不变模式天生就是多线程友好的,它的核心思想是,一个对象一旦被创建,则它的内部状态将永远不会发生改变

  • 浅谈java String不可变的好处

    一.java内部String类的实现: java 8: public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; } java 9 及之后:(使用coder标识了编码) public final class Stri

  • Java的string类为什么是不可变的

    答案一: 最流行的Java面试题之一就是:什么是不可变对象(immutable object),不可变对象有什么好处,在什么情况下应该用,或者更具体一些,Java的String类为什么要设成immutable类型?不可变对象,顾名思义就是创建后不可以改变的对象,典型的例子就是Java中的String类. 复制代码 代码如下: String s = "ABC";  s.toLowerCase(); 如上s.toLowerCase()并没有改变"ABC"的值,而是创建了

  • JAVA不可变类(immutable)机制与String的不可变性(推荐)

    一.不可变类简介 不可变类:所谓的不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值.如JDK内部自带的很多不可变类:Interger.Long和String等. 可变类:相对于不可变类,可变类创建实例后可以改变其成员变量值,开发中创建的大部分类都属于可变类. 二.不可变类的优点 说完可变类和不可变类的区别,我们需要进一步了解为什么要有不可变类?这样的特性对JAVA来说带来怎样的好处? 1.线程安全 不可变对象是线程安全的,在线程之间可以相互共享,不需要利用特殊机制来保证同步问题,因

  • 浅谈为什么Java里面String类是不可变的

    在Java里面String类型是不可变对象,这一点毫无疑问,那么为什么Java语言的设计者要把String类型设计成不可变对象呢?这是一个值得思考的问题 Java语言的创建者James Gosling,曾经在一次采访中被人问到:什么时候应该使用不可变对象(immutable object),他回答:任何可以使用的时候都会使用. 在这之前,我们先来简单了解一下,什么是不可变对象? 不可变对象指的是在对象创建之后,对象的内部状态以及对象的内存指针地址都不不能被改变.在Java里面final关键字就是

  • Java String源码分析并介绍Sting 为什么不可变

    Java String源码分析 什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的.不能改变状态的意思是,不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不能指向其他的对象,引用类型指向的对象的状态也不能改变. 区分对象和对象的引用 对于Java初学者, 对于String是不可变对象总是存有疑惑.看下面代码: String s =

  • Java string不可变原理实例解析

    我最喜欢的 Java 面试问题,不好回答,但同时也非常有用.一些面试者也常问这个问题,为什么 String 在 Java 中是 final 的. 字符串在 Java 中是不可变的,因为 String 对象缓存在 String 池中.由于缓存的字符串在多个客户之间共享,因此始终存在风险,其中一个客户的操作会影响所有其他客户. 例如,如果一段代码将 String "Test" 的值更改为 "TEST",则所有其他客户也将看到该值.由于 String 对象的缓存是性能的重

  • 分析Java中为什么String不可变

    常量池 Java中我们创建String对象有两种基本方法. String str1 = "zxhtom"; String str2 = new String("zxhtom"); 上面两种方式我们创建了两个String变量 . 但是第一种通过双引号创建的zxhtom这个对象我们称之为常量 . 在JVM中是存储在一块叫[常量池]中的.而第二种str2是我们称之为普通变量.new一次就在JVM中开辟一块内存. [常量池]的作用就是复用,当同样的内容再次被通过常量方式创建

  • Java中关于String的全面解析

    前言 基于字符串String在java中的地位,关于String的常识性知识就不多做介绍了,我们先来看一段代码 public class Test { public static void main(String[] args) { String a = "abc"; String b = "abc"; String c = new String("abc"); System.out.println(a==b); System.out.print

  • Java中关于String StringBuffer StringBuilder特性深度解析

    1.String String类:字符串是常量,使用一对""引起来表示.他们的值在创建之后不能修改. 1.String声明为final的,不可被继承 2.String实现了Serializable接口,表示字符串时支持序列化的. 实现了Comparable接口:表示String可以比较大小 3.String内部定义了final char[] value用于存储字符串数据 4.String:代表不可变的字符序列.简称:不可变性 体现: 1.当对字符串重新赋值时,需要重写指定内存区域赋值,

  • 分析java 中AspectJ切面执行两次的原因

    分析java 中AspectJ切面执行两次的原因 背景 转眼之间,发现博客已经将近半年没更新了,甚是惭愧.话不多说,正如标题所言,最近在使用AspectJ的时候,发现拦截器(AOP切面)执行了两次了.我们知道,AspectJ是AOP的一种解决方案,本质上是通过代理类在目标方法执行通知(Advice),然后由代理类再去调用目标方法.所以,从这点讲,拦截器应该只会执行一次.但是在测试的时候发现拦截器执行了两次. 问题重现 既然问题已经明了,那么可以通过代码简单重现这个问题,从而更深层次分析到底是什么

  • 深入了解java中的string对象

    这里来对Java中的String对象做一个稍微深入的了解. Java对象实现的演进 String对象是Java中使用最频繁的对象之一,所以Java开发者们也在不断地对String对象的实现进行优化,以便提升String对象的性能. Java6以及之前版本中String对象的属性 在Java6以及之前版本中,String对象是对char数组进行了封装实现的对象,其主要有4个成员成员变量,分别是char数组.偏移量offset.字符数量count和哈希值hash.String对象是通过offset和

  • 分析java中全面的单例模式多种实现方式

    一.单例模式的思想 想整理一些 java 并发相关的知识,不知道从哪开始,想起了单例模式中要考虑的线程安全,就从单例模式开始吧.以前写过单例模式,这里再重新汇总补充整理一下,单例模式的多种实现. 单例模式的主要思想是: 将构造方法私有化( 声明为 private ),这样外界不能随意 new 出新的实例对象: 声明一个私有的静态的实例对象,供外界使用: 提供一个公开的方法,让外界获得该类的实例对象 这种说法看上去没错,但也好像不太准确.其实,就算外界能随意 new 出新的实例对象,但只要我们保证

  • 分析Java中Map的遍历性能问题

    一.引言 我们知道java HashMap的扩容是有成本的,为了减少扩容的次数和成本,可以给HashMap设置初始容量大小,如下所示: HashMap<string, integer=""> map0 = new HashMap<string, integer="">(100000); 但是在实际使用的过程中,发现性能不但没有提升,反而显著下降了!代码里对HashMap的操作也只有遍历了,看来是遍历出了问题,于是做了一番测试,得到如下结果:

  • 分析Java中的类加载问题

    目录 一.Java类的加载顺序 二.类加载过程 三.被动引用中和类静态初始化的关系 四.类加载器双亲委派 一.Java类的加载顺序 引用1个网上的经典例子,并做稍许改动,以便大家更好地理解. public class Animal { private int i = test(); private static int j = method(); static { System.out.println("a"); } Animal(){ System.out.println("

  • Java中字符串String的+和+=及循环操作String原理详解

    String对象是不可变的:意思就是无论是对String的新增或修改,出现一个全新的String内容时,都意味着诞生了一个新的对象.但是如果内容不变的话,增加的只是对象的引用而已. 例如: String a = "ljh"; String b = "ljh"; String c = "ljh"; System.out.println(a==b); System.out.println(b==c); 结果都是true 但是这种不可变性会产生一些性能

随机推荐