精华内容
下载资源
问答
  • String为什么设计成不可变的!

    千次阅读 2018-12-11 17:02:39
    我们来分析下为什么Java中String设计成不可变的。 首先我们来看一段代码: public class Test { public static void main(String []args) { String s1 = "abcdef"; System.out.println(s1); ...

    String 对象是不可变的,字符串是常量,不是变量。我们来分析下为什么Java中String要设计成不可变的。

    首先我们来看一段代码:

    public class Test {
        public static void main(String []args)
        {
            String s1 = "abcdef";
            System.out.println(s1);
            s1 = "123456";
            System.out.println(s1);
        }
    }
    

    打印结果:
    在这里插入图片描述
    结果不是变了吗? 为啥还说String是不可变的呢?
    s1 仅仅是一个对象引用,并不是对象的本身。对象是在内存中的一块内存区域,而s1是指向这块区域的一个引用。创建对象s1时,s1指向内存中的”abcdef“,当执行了 s1 = "123456"后,s1又指向内存中的”123456“,而”abcdef“并没有改变,还在内存中存在。

    String 本身提供了一个replace()方法,不是可以改变内容吗?

    public class Test {
        public static void main(String []args)
        {
            String s1 = "abcdef";
            System.out.println(s1);
            s1.replace("a","A");
            System.out.println(s1);
        }
    }
    

    结果:
    在这里插入图片描述
    字符串并没改变。
    改变下写法:

    public class Test {
        public static void main(String []args)
        {
            String s1 = "abcdef";
            System.out.println(s1);
            s1 = s1.replace("a","A");
            System.out.println(s1);
        }
    }
    

    结果:
    在这里插入图片描述
    这样的话,数值就会改变了。s1.replace(“a”,“A”) 会在内存中产生一个新的对象”Abcdef“,s1 = s1.replace(“a”,“A”)执行后,s1指向内存中这块新区域,所以内容改变了,原来的”abcdef“并没有改变,还保存在内存中。

    String 是如何实现不可变的呢?

    首先看下成员变量:

    /** The value is used for character storage. */
    private final char value[];
    
    /** Cache the hash code for the string */
    private int hash; // Default to 0
    
    1. value数组是用来存放字符的,hash用来存放该对象的哈希值。
    2. value 对象被private final 修饰,hash 被private修饰,String类并没有对外提供value和hash的set方法,所以外部无法修改。并且通过final关键字保证只要初始话数值了,就无法在改变了。

    所以认为String对象是不可改变的。但是value本身又是一个引用,它指向存放真正数据的数组对象。

    不可变对象的好处
    1. 不可变对象更容易构造,测试与使用;
    2. 真正不可变对象都是线程安全的;
    3. 不可变对象的使用没有副作用(没有保护性拷贝);
    4. 对象变化的问题得到了避免;
    5. 不可变对象的失败都是原子性的;
    6. 不可变对象更容易缓存,且可以避免null引用;
    7. 不可变对象可以避免时间上的耦合;

    String,StringBuffer,StringBuilder,都是final类,不允许被继承,在本质上都是字符数组。不同的是String长度不可变,其他两个在添加字符串时可以增加。String在每次拼接时都会返回一个新的实例,StringBuffer和StringBuilder 通过append添加数据是在原对象添加。所以在进行大量字符串操作时,不推荐使用String
    StringBuffer是线程安全的,因为它在append方法前增加synchronized修饰符,起同步作用,但是效率比StringBuilder 低。

    String的这种不可变,我们可以通过其他方法突破的

    前面我们提到String类是通过char[] value 来存储的。value本身就是一个引用,虽然不能改变它的引用地址,我们可以修改真正数组数据。因为value是私有,我们通过反射来处理。

    public class Test {
        public static void main(String []args)
        {
            try {
                String s1 = "abcdef";
                System.out.println(s1);
                Field valueField = null;
                valueField = s1.getClass().getDeclaredField("value");
                valueField.setAccessible(true);
    
                char[] value = (char[]) valueField.get(s1);
                value[0] = '1';
                value[2] = '2';
                value[4] = '3';
                System.out.println("s = " + s1);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
    

    结果:
    在这里插入图片描述

    展开全文
  • 为什么String设计成不可变

    千次阅读 2018-08-16 22:11:22
    在Java中将String设计成不可变的是综合考虑到各种因素的结果,想要理解这个问题,需要综合内存,同步,数据结构以及安全等方面的考虑. 在下文中,我将各种原因做一个小结。 1. 字符串常量池的需要 字符串常量池...

         在Java中将String设计成不可变的是综合考虑到各种因素的结果,想要理解这个问题,需要综合内存,同步,数据结构以及安全等方面的考虑. 在下文中,我将为各种原因做一个小结。

    1. 字符串常量池的需要

    字符串常量池(String pool, String intern pool, String保留池) 是Java堆内存中一个特殊的存储区域, 当创建一个String对象时,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。

    如下面的代码所示,将会在堆内存中只创建一个实际String对象.

    String s1="abc";
    String s2="abc";

    假若字符串对象允许改变,那么将会导致各种逻辑错误,比如改变一个对象会影响到另一个独立对象. 严格来说,这种常量池的思想,是一种优化手段.

    思考: 假若代码如下所示,s1和s2还会指向同一个实际的String对象吗?

    String s1="abc";
    String s2="ab"+"c";

    答案是肯定的,现代编译器会进行常规的优化, 所以他们都会指向常量池中的同一个对象。

    2.允许String对象缓存HashCode
    Java中String对象的哈希码被频繁地使用, 比如在hashMap 等容器中。

    字符串不变性保证了hash码的唯一性,因此可以放心地进行缓存.这也是一种性能优化手段,意味着不必每次都去计算新的哈希码. 在String类的定义中有如下代码:

    3.安全性

    String被许多的Java类(库)用来当做参数,例如 网络连接地址URL,文件路径path,还有反射机制所需要的String参数等, 假若String不是固定不变的,将会引起各种安全隐患。

    4.总结

    String不可变的原因包括 设计考虑,效率优化问题,以及安全性这三大方面. 

     

    展开全文
  • 为什么String设计成不可变的?

    万次阅读 多人点赞 2013-11-18 20:30:03
    翻译人员: 铁锚 翻译日期: 2013年11月18日 原文链接: Why ... 在Java中将String设计成不可变的是综合考虑到各种因素的结果,想要理解这个问题,需要综合内存,同步,数据结构以及安全等方面的考虑.

    翻译人员: 铁锚

    翻译日期: 2013年11月18日

    原文链接: Why string is immutable in Java ?


    这是一个老生常谈的话题(This is an old yet still popular question). 在Java中将String设计成不可变的是综合考虑到各种因素的结果,想要理解这个问题,需要综合内存,同步,数据结构以及安全等方面的考虑. 在下文中,我将为各种原因做一个小结。

    1. 字符串常量池的需要

    字符串常量池(String pool, String intern pool, String保留池) 是Java堆内存中一个特殊的存储区域, 当创建一个String对象时,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。

    如下面的代码所示,将会在堆内存中只创建一个实际String对象.

    String s1 = "abcd";
    String s2 = "abcd";
    示意图如下所示:

    图1

    假若字符串对象允许改变,那么将会导致各种逻辑错误,比如改变一个对象会影响到另一个独立对象. 严格来说,这种常量池的思想,是一种优化手段.

    思考: 假若代码如下所示,s1和s2还会指向同一个实际的String对象吗?

    String s1= "ab" + "cd";
    String s2= "abc" + "d";
    也许这个问题违反新手的直觉, 但是考虑到现代编译器会进行常规的优化, 所以他们都会指向常量池中的同一个对象. 或者,你可以用 jd-gui 之类的工具查看一下编译后的class文件.

    2. 允许String对象缓存HashCode
    Java中String对象的哈希码被频繁地使用, 比如在hashMap 等容器中。

    字符串不变性保证了hash码的唯一性,因此可以放心地进行缓存.这也是一种性能优化手段,意味着不必每次都去计算新的哈希码. 在String类的定义中有如下代码:

    private int hash;//用来缓存HashCode
    3. 安全性
    String被许多的Java类(库)用来当做参数,例如 网络连接地址URL,文件路径path,还有反射机制所需要的String参数等, 假若String不是固定不变的,将会引起各种安全隐患。

    假如有如下的代码:

    boolean connect(string s){
        if (!isSecure(s)) { 
    throw new SecurityException(); 
    }
        // 如果在其他地方可以修改String,那么此处就会引起各种预料不到的问题/错误 
        causeProblem(s);
    }


    总体来说, String不可变的原因包括 设计考虑,效率优化问题,以及安全性这三大方面. 事实上,这也是Java面试中的许多 "为什么" 的答案。
    相关文章 :

    1. String对象不可改变的特性
    2. String is passed by “reference” in Java
    3. 十大常见Java String问题
    4. Java中Set的contains()方法

    展开全文
  • 面试官:String为什么设计不可变的?

    千次阅读 多人点赞 2020-06-20 16:17:19
    从哪看出来String类是不可变的? public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char...

    在这里插入图片描述

    从哪看出来String类是不可变的?

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
        /** The value is used for character storage. */
        private final char value[];
    }
    

    String类的值是保存在value数组中的,并且是被private final修饰的

    1. private修饰,表明外部的类是访问不到value的,同时子类也访问不到,当然String类不可能有子类,因为类被final修饰了
    2. final修饰,表明value的引用是不会被改变的,而value只会在String的构造函数中被初始化,而且并没有其他方法可以修改value数组中的值,保证了value的引用和值都不会发生变化

    final关键字的作用有如下几种

    1. final修饰类时,表明这个类不能被继承
    2. final修饰方法,表明方法不能被重写
    3. final修饰变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能改变;如果是对象类型的变量,只能保证它的引用不变,但对象的内容是可以改变的

    在Java中数组也是对象,数组即使被final修饰,内容还是可以改变的

    所以我们说String类是不可变的。

    而很多方法,如substring并不是在原来的String类上进行操作,而是生成了新的String类

    public String substring(int beginIndex) {
    	if (beginIndex < 0) {
    		throw new StringIndexOutOfBoundsException(beginIndex);
    	}
    	int subLen = value.length - beginIndex;
    	if (subLen < 0) {
    		throw new StringIndexOutOfBoundsException(subLen);
    	}
    	return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }
    

    为什么String被设置为不可变的?

    字符串常量池

    字符串常量池可以节省大量的内存空间。如果String类可变就不可能有字符串常量池

    字符串常量池放在哪?

    jdk1.7之前的不讨论,从jdk1.7开始,字符串常量池就开始放在堆中,然后本文的所有内容都是基于jdk1.8的

    下面这个代码还是经常被问到的

    String str1 = "abc";
    String str2 = "abc";
    String str3 = new String("abc");
    String str4 = new String("abc");
    // true
    System.out.println(str1 == str2);
    // false
    System.out.println(str1 == str3);
    // false
    System.out.println(str3 == str4);
    

    内存中的结构如下
    在这里插入图片描述
    其中常量池中存的是引用

    解释一下上面代码的输出,Java中有2种创建字符串对象的方式

    String str1 = "abc";
    String str2 = "abc";
    // true
    System.out.println(str1 == str2);
    

    采用字面值的方式创建一个字符串时,JVM首先会去字符串池中查找是否存在"abc"这个对象的引用

    如果不存在,则在堆中创建"abc"这个对象,并将其引用添加到字符串常量池(实际上是将引用放到哈希表中),随后将引用赋给str1

    如果存在,则不创建任何对象,直接将池中"abc"对象的引用返回,赋给str2。因为str1、str2指向同一个对象,所以结果为true。

    String str3 = new String("abc");
    String str4 = new String("abc");
    // false
    System.out.println(str3 == str4);
    

    采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"abc"这个字符串对象的引用

    如果没有,则先在堆中创建一个"abc"字符串对象,并将引用添加到字符串常量池,随后将引用赋给str3

    如果有,则不往池中放"abc"对象的引用,直接在堆中创建一个"abc"字符串对象,然后将引用赋给str4。这样,str4就指向了堆中创建的这个"abc"字符串对象;

    因为str3和str4指向的是不同的字符串对象,结果为false。

    缓存HashCode

    String类在被创建的时候,hashcode就被缓存到hash成员变量中,因为String类是不可变的,所以hashcode是不会改变的。这样每次想使用hashcode的时候直接取就行了,而不用重新计算,提高了效率

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence {
    
        /** Cache the hash code for the string */
        private int hash; // Default to 0
    	
    }
    

    可以用作HashMap的key

    由于String类不可变的特性,所以经常被用作HashMap的key,如果String类是可变的,内容改变,hashCode也会改变,当根据这个key从HashMap中取的时候有可能取不到value,或者取到错的value

    线程安全

    不可变对象天生就是线程安全的,这样可以避免在多线程环境下对String做同步操作

    欢迎关注

    在这里插入图片描述

    参考博客

    [1]https://mp.weixin.qq.com/s?src=11&timestamp=1592637033&ver=2411&signature=alSwI0tpXmnpwBII3UYs1lFZqTk2rx1VymKrT-tfFt86HNwLbLHfMqxloqZhERqHtwi-Ezrx6ksZ-hL19oc0xbqVzXw2yicU77LuqYkFMBlYoBTohvdysefGXMHY6W9l&new=1
    好文
    [2]https://www.ershicimi.com/p/72759faff05aeb5279ffbec79e6a7b52

    展开全文
  • java中String设计成不可变的原因

    千次阅读 2018-07-22 00:55:08
    1.什么是【不可变】?  String不可变很简单,如下图,给一个已有...2.String为什么不可变?从原理上分析。  翻开JDK源码,java.lang.String类起手前三行,是这样写的: public final class String implements...
  • 1.什么是不可变String不可变很简单,如下图,给一个已有字符串“abcd”第...2.String为什么不可变? 翻开JDK源码,java.lang.String类起手前三行,是这样写的: public final class String implements java.io.Ser
  • 我们知道在Java中,String不可变的、final的。Java在运行时也保存了一个字符串池(String pool),这使得String成为了一个特别的类。 主要是为了 “ 效率 ” 和 “ 安全性 ” 的缘故。 若 String 允许...
  • 先贴一下String类的申明代码: public final class String implements java.io.Serializable, Comparable&lt;String&gt;, CharSequence {} 它最大的一个特点是被final修饰了。我们先看看官方怎么解释: ...
  • Java中String为什么不可变的?

    千次阅读 多人点赞 2018-10-29 23:11:53
    Java中String为什么不可变的?
  • 【申明:以下内容翻译自... 欢迎阅读原文:Why string is immutable in Java ? ...为什么Java中的String设计成不可变的? 这是一个老生常谈的问题了。在java中将String设计成不可变的原因有很多,然而一个好
  • 字符串在Java中是不可变的,因为String对象缓存在String池中。由于缓存的字符串在多个客户之间共享,因此始终存在风险,其中一个客户的操作会影响所有其他客户。例如,如果一段代码将String “Test”的值更改...
  • 为什么String设计成不可变

    千次阅读 2018-07-19 10:13:49
    String的构成 1public final class String 2 implements java.io.Serializable, Comparable&lt;String&gt;, CharSequence { 3 /** The value is used for character storage. */ 4 ...
  • 为什么String设计不可变

    千次阅读 2015-06-05 17:58:59
    对象不可变定义 不可变对象是指对象的状态在被初始化以后,在整个对象的生命周期内,可改变。 如何不可变 通常情况下,在java中通过以下步骤实现不可变 对于属性提供设值方法 所有的属性定义private final ...
  • String为什么不可变的? String、StringBuffer与StringBuffer区别 String是字符串常量 StringBuffer和StringBuilder是字符串变量 有时候大家会很疑惑,为什么String会是常量,如下代码: 1. String s = &...
  •  相信大家在开发中,对于final修饰符都比较常见,它会将修饰的变量固定不可重复赋值。但是我们是否思考过被它所修饰属性变量或类存储在哪里呢?下面已我将用比较有趣的问答形式,让大家对final有一个全面的认识。在...
  • 对Java String不可变的理解

    千次阅读 2019-01-08 13:27:41
    java的String为什么要设置成不可变类型? 什么是不可变对象。不可变对象有什么好处? 1、不可变对象,顾名思义就是创建后的对象可以改变,典型的例子有java中的String类型。注意,是对象不可变,并非引用不可...
  • 前几天,有个实习生问我,String为什么设计成不可变的,说他看见网上的都说可变。我看了看他,说:那篇博客你没看完吧!他挠了挠头回答说:没有!我又问他:知道string类有个变量value么?他说知道,我又问这个...
  • 最近突然被问到String为什么设计不可变,当时有点懵,这个问题一直像bug一样存在,竟然没有发现,没有思考到,在此总结一下。 1.String不可变 String类被final修饰,是可继承和修改的。当一个String变量被...
  • 为什么String类型是不可变的?

    千次阅读 2013-11-22 01:18:45
    这篇文章将对字符串的驻留做详细的解释和剖析。 引自:...原文:这是一个很久以前就备受瞩目的问题,有很多原因导致String在Java中是不可变的量,首先要解决这个问题,取决于你对内存布局,同步问题,
  • 熟悉Java的都知道String类是不可变,但String为什么设计成不可变类,如何做到不可变没有仔细想过。 String为什么设计成不可变类? 1.Java字符串池的设计方式。  String s1="abc"; String s2="abc"; Java通过字符...
  • 为什么Java里面String类是不可变

    千次阅读 2019-01-06 18:39:28
    在Java里面String类型是不可变对象,这一点毫无疑问,那么为什么Java语言的设计者要把String类型设计成不可变对象呢?这是一个值得思考的问题 Java语言的创建者James Gosling,曾经在一次采访中被人问到:什么时候...
  • String不可变以及不可变类总结

    千次阅读 2017-10-01 20:11:38
    String类在java中是immutable(不可变),因为它被关键字final修饰。... 要了解String类创建的实例为什么不可变,首先要知道final关键字的作用:final的意思是“最终,最后”。final关键字可以修饰类、方法...
  • String为什么设计成final

    千次阅读 2017-06-04 12:48:32
    前言:今天突然看到一个问题为什么...源码中对String为什么设计成final的解释:Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because
  • 为什么Java中字符串被设计成不可变的?

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 283,868
精华内容 113,547
关键字:

为什么string设计成不可变