java中可变字符串和不可变字符串有啥区别

Posted

技术标签:

【中文标题】java中可变字符串和不可变字符串有啥区别【英文标题】:What is difference between mutable and immutable String in javajava中可变字符串和不可变字符串有什么区别 【发布时间】:2014-09-28 02:26:42 【问题描述】:

据我所知,

可以更改可变字符串,并且 不可变的字符串无法更改。

这里我想这样改变String的值,

String str="Good";
str=str+" Morning";

另一种方式是,

StringBuffer str= new StringBuffer("Good");
str.append(" Morning");

在这两种情况下,我都试图改变str 的值。谁能告诉我,这两种情况有什么区别,并让我清楚地了解可变和不可变对象。

【问题讨论】:

在 java 中字符串是不可变的。没有可变字符串。 String is immutable. What exactly is the meaning? 的可能重复项 @TheLostMind 可变为StringBuffer 对象,String 为不可变对象对 @Raghu- No. StringBuffer 对象不是 可变 字符串。一个字符串一旦创建就永远是不可变的。 @TheLostMind 是的,我知道了,我不是说StringBuffermutable String,我是说StringBuffermutable Object。我现在是吗? 【参考方案1】:

案例一:

String str = "Good";
str = str + " Morning";

在上面的代码中,您创建了 3 个String 对象。

    “好”它进入 字符串池。 “Morning”它也进入了字符串池。 通过连接“Good”和“Morning”创建的“Good Morning”。这家伙继续

注意:字符串总是不可变的。不存在可变字符串之类的东西。 str 只是一个引用,它最终指向“早安”。实际上,您不是在处理1 对象。你有 3 不同的 String 对象。


案例2:

StringBuffer str = new StringBuffer("Good"); 
str.append(" Morning");

StringBuffer 包含一个字符数组。它String 相同。 上面的代码将字符添加到现有数组中。实际上,StringBuffer 是可变的,它的 String 表示不是。

【讨论】:

你能告诉我为什么“GoodMorning”进入堆而不是字符串池。 ? @DilanG - 在内部(如果字符串文字未标记为 final),使用 StringBuilder/StringBuffer 进行字符串连接 万一2str.append(" Morining")"Morning"是否存储在字符串池中?【参考方案2】:

java中可变字符串和不可变字符串有什么区别

不可变存在,可变不存在。

【讨论】:

StringBuffer 扮演可变字符串的角色。注意String 和只是 string. 之间的区别 @WilliamF.Jameson - 不,StringBuffer 不扮演可变字符串的角色。它是一个可以转换为字符串的数组。一旦你在它上面调用toString(),然后向它添加字符并再次调用toString(),你将拥有2个不同的字符串对象。 @TheLostMind 请仔细阅读我的评论:stringString 不同。一个是通用概念,另一个是 Java 类。 StringBuffer 绝对是 Java 中可变字符串的目的。【参考方案3】:

在 Java 中,所有字符串都是不可变的。当您尝试修改String 时,您真正要做的是创建一个新的。但是,当您使用StringBuilder 时,您实际上是在修改内容,而不是创建新内容。

【讨论】:

【参考方案4】:

Java Strings 是不可变的。

在您的第一个示例中,您将 reference 更改为 String,从而为其分配了另外两个 Strings 组合的值:str + " Morning"

相反,StringBuilderStringBuffer 可以通过其方法进行修改。

【讨论】:

【参考方案5】: Mutable    :- 可变的 Immutable :- 可变

String 在 Java 中是不可变的。然而,在编程上下文中 mutable 意味着什么是第一个问题。考虑下课,

public class Dimension 
    private int height;

    private int width;

    public Dimenstion() 
    

    public void setSize(int height, int width) 
        this.height = height;
        this.width = width;
    

    public getHeight() 
        return height;
    

    public getWidth() 
        return width;
    

现在在创建Dimension 的实例后,我们可以随时更新它的属性。请注意,如果任何属性,在其他意义上的状态,可以更新类的实例,那么它被称为是可变的。我们总是可以跟随,

Dimension d = new Dimension();
d.setSize(10, 20);// Dimension changed
d.setSize(10, 200);// Dimension changed
d.setSize(100, 200);// Dimension changed

让我们看看在 Java 中创建字符串的不同方式。

String str1 = "Hey!";
String str2 = "Jack";
String str3 = new String("Hey Jack!");
String str4 = new String(new char[] 'H', 'e', 'y', '!');
String str5 = str1 + str2;
str1 = "Hi !";
// ...

所以,

    str1str2 是在字符串常量池中创建的字符串字面量 str3str4str5 是放在堆内存中的字符串对象 str1 = "Hi!"; 在字符串常量池中创建"Hi!",它与"Hey!" 的引用完全不同,str1 更早引用。

这里我们正在创建字符串字面量或字符串对象。两者是不同的,我建议您阅读以下帖子以了解更多信息。

Difference between string object and string literal

在任何 String 声明中,都有一件事是常见的,它不会修改,但会被创建或转移到另一个。

String str = "Good"; // Create the String literal in String pool
str = str + " Morning"; // Create String with concatenation of str + "Morning"
|_____________________|
       |- Step 1 : Concatenate "Good"  and " Morning" with StringBuilder
       |- Step 2 : assign reference of created "Good Morning" String Object to str

String 是如何变得不可变的?

这是不变的行为,意味着一旦分配的值不能以任何其他方式更新。 String 类在内部保存字符数组中的数据。此外,类被创建为不可变的。看看这个定义不可变类的策略。

移动参考并不意味着你改变了它的价值。如果您可以更新 String 类中幕后的字符数组,它将是可变的。但实际上该数组将被初始化一次,并且在整个程序中它保持不变。

为什么 StringBuffer 是可变的?

正如您已经猜到的,StringBuffer 类本身是可变的,因为您可以直接更新它的状态。与 String 类似,它也在字符数组中保存值,您可以通过不同的方法操作该数组追加、删除、插入等直接更改字符值数组。

【讨论】:

【参考方案6】:

当你说str时,你应该小心你的意思:

你的意思是变量str

还是说str引用的对象

在您的StringBuffer 示例中,您不会更改str 的值,而在您的String 示例中,您不会更改String 对象的状态。

体验这种差异的最令人心酸的方式是这样的:

static void change(String in)  
  in = in + " changed";


static void change(StringBuffer in) 
  in.append(" changed");


public static void main(String[] args) 
   StringBuffer sb = new StringBuffer("value");
   String str = "value";
   change(sb);
   change(str);
   System.out.println("StringBuffer: "+sb);
   System.out.println("String: "+str);

【讨论】:

【参考方案7】:

在 Java 中,所有字符串都是immutable(不能更改)。 当你试图修改一个字符串时,你真正在做的是创建一个新的

我们可以通过以下方式创建字符串对象

    使用字符串字面量

    String str="java";
    

    使用新关键字

    String str = new String("java");
    

    使用字符数组

    char[] helloArray =  'h', 'e', 'l', 'l', 'o', '.' ;
    
    String helloString = new String(helloArray);   
    

字符串不变性,简单来说就是不可修改或不可改变

举个例子

我正在将值初始化为字符串文字 s

String s="kumar";

下面我将使用 hashcode() 显示位置地址的十进制表示

System.out.println(s.hashCode());

只打印一个字符串 s 的值

System.out.println("value "+s);

好的,这次我将值“kumar”初始化为 s1

String s1="kumar";   // what you think is this line, takes new location in the memory ??? 

好的,让我们通过显示我们创建的 s1 对象的哈希码来检查

System.out.println(s1.hashCode());

好的,让我们检查下面的代码

String s2=new String("Kumar");
    System.out.println(s2.hashCode());  // why this gives the different address ??

好的,最后检查下面的代码

String s3=new String("KUMAR");
    System.out.println(s3.hashCode());  // again different address ???

是的,如果您看到字符串“s”和“s1”具有相同的哈希码,因为“s”和“s1”持有的值与“kumar”相同

让我们考虑一下 String 's2' 和 's3' 这两个 Strings hashcode 在某种意义上看起来是不同的,它们都存储在不同的位置,因为您看到它们的值不同。

因为 s 和 s1 哈希码是相同的,因为它们的值相同并且存储在相同的位置。

示例 1: 试试下面的代码,逐行分析

public class StringImmutable 
public static void main(String[] args) 

    String s="java";
    System.out.println(s.hashCode());
    String s1="javA";
    System.out.println(s1.hashCode());
    String s2=new String("Java");
    System.out.println(s2.hashCode());
    String s3=new String("JAVA");
    System.out.println(s3.hashCode());


示例 2:尝试以下代码并逐行分析

public class StringImmutable 
    public static void main(String[] args) 

        String s="java";
        s.concat(" programming");  // s can not be changed "immutablity"
        System.out.println("value of s "+s);
        System.out.println(" hashcode of s "+s.hashCode());

        String s1="java";
        String s2=s.concat(" programming");   // s1 can not be changed "immutablity" rather creates object s2
        System.out.println("value of s1 "+s1);
        System.out.println(" hashcode of s1 "+s1.hashCode());  

        System.out.println("value of s2 "+s2);
        System.out.println(" hashcode of s2 "+s2.hashCode());

    

好,我们来看看mutable和immutable有什么区别。

可变(它会改变)与不可变(它不能改变)

public class StringMutableANDimmutable 
    public static void main(String[] args) 


        // it demonstrates immutable concept
        String s="java";
        s.concat(" programming");  // s can not be changed (immutablity)
        System.out.println("value of s ==  "+s); 
        System.out.println(" hashcode of s == "+s.hashCode()+"\n\n");


        // it demonstrates mutable concept
        StringBuffer s1= new StringBuffer("java");
        s1.append(" programming");  // s can be changed (mutablity)
        System.out.println("value of s1 ==  "+s1); 
        System.out.println(" hashcode of s1 == "+s1.hashCode());


    

还有什么问题吗??请写在...

【讨论】:

请不要使用 StringBuffer,因为它在 2004 年被 StringBuilder 取代。 @PeterLawrey 谢谢,我刚才演示了。【参考方案8】:

我用输出 cmets 修改了 william 的代码以便更好地理解

   static void changeStr(String in)  
      in = in+" changed";
      System.out.println("fun:"+in); //value changed 
    
    static void changeStrBuf(StringBuffer in) 
      in.append(" changed");   //value changed
    

    public static void main(String[] args) 
       StringBuffer sb = new StringBuffer("value");
       String str = "value";
       changeStrBuf(sb);
       changeStr(str);
       System.out.println("StringBuffer: "+sb); //value changed
       System.out.println("String: "+str);       // value 
    

在上面的代码中,查看 main() 和 changeStr() 中 str 的值,即使你更改了 changeStr() 中 str 的值,它只影响该函数,但在 main 函数中,值是没有改变,但不是在StringBuffer的情况下..

在 StringBuffer 中更改的值作为全局影响..

因此 String 是不可变的,而 StringBuffer 是可变的...

在 Simple 中,您更改为 String Object 的任何内容都只会影响该函数,方法是转到 String Pool。但没有改变...

【讨论】:

【参考方案9】:

可变变量是其值可能在原地改变的变量,而在不可变变量中,值的改变不会原地发生。修改不可变变量将重建相同的变量。

【讨论】:

【参考方案10】:

可变意味着您将保存相同的引用到变量并更改其内容但不可变您不能更改内容但您将声明新引用包含新的和旧的变量的值

不可变 -> 字符串

String x = "value0ne";// adresse one x += "valueTwo"; //an other adresse adresse two 堆内存变化的地址。

可变 -> StringBuffer - StringBuilder StringBuilder sb = new StringBuilder(); sb.append("valueOne"); // adresse One sb.append("valueTwo"); // adresse One

某人仍在同一个地址,我希望此评论对您有所帮助

【讨论】:

以上是关于java中可变字符串和不可变字符串有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

区块链和不可变链表有啥区别?

String 与StringBuilder有啥区别

Python札记3:可变对象和不可变对象

linux 可变类型与不可变类型

python中的可变参数和不可变参数

字符串详解:整型可变数据类型和不可变数据类型进制转换索引切片步长字符串方法进制转换