Java 为什么字符串变量在函数内部修改时不变,而列表却不变

Java 为什么字符串变量在函数内部修改时不变,而列表却不变,java,c#,string,list,arraylist,Java,C#,String,List,Arraylist,想象一下这种情况: 您有一个字符串,并调用一个函数,该函数将此字符串作为参数接收,并更改函数中的值。函数外部的字符串值不会更改,只会在函数内部更改 myList = new List<string>() { "new list" }; 但是,如果对列表执行相同的操作,则列表内容将在函数之外进行修改 myList = new List<string>() { "new list" }; 为什么会这样 查找此代码以获取回购: using System; using Sys

想象一下这种情况:

您有一个字符串,并调用一个函数,该函数将此字符串作为参数接收,并更改函数中的值。函数外部的字符串值不会更改,只会在函数内部更改

myList = new List<string>() { "new list" };
但是,如果对列表执行相同的操作,则列表内容将在函数之外进行修改

myList = new List<string>() { "new list" };
为什么会这样

查找此代码以获取回购:

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<string> list = new List<string>();
        list.Add("1");
        string text = "text";
        ChangeSomethingInText(text);
        Console.WriteLine(text);
        ChangeSomethingInList(list);
        foreach (var i in list)
        {
            Console.WriteLine(i);
        }
    }


    public static void ChangeSomethingInText(string text)
    {
        text = "Text changed";
    }

    public static void ChangeSomethingInList(List<string> myList)
    {
         myList.Add("From change");
    }
}
结果是:文本仍然是文本,但列表中有一个新元素

我在C语言中用一个字符串对一个列表进行了测试,在Java中用一个字符串对一个具有相同行为的ArrayList进行了测试

您有一个字符串并调用了一个函数,该函数将该字符串作为参数接收并更改函数中的值

myList = new List<string>() { "new list" };
从技术上讲,您不能更改字符串的值,因为字符串是不可变的。他们没有办法让你改变他们。您只能创建新字符串并更改变量,使其指向新字符串

这就是文本=新值;做它创建一个全新的字符串对象,并更改变量文本,使其指向新字符串。原始字符串仍在内存中的某个位置,指向它的任何其他变量仍指向它

这就是为什么:

函数外部的字符串值不会更改,只会在函数内部更改

myList = new List<string>() { "new list" };
因为在调用函数时,传递了一个名为text的引用副本。在函数内部,您将函数的引用副本更改为指向其他字符串,但外部引用不受影响

但是,如果对列表执行相同的操作,则列表内容将在函数之外进行修改

myList = new List<string>() { "new list" };
不,如果您为列表的引用指定了一个新值,那么这种更改只在函数内部发生

myList = new List<string>() { "new list" };

这是不能对字符串执行的操作。string类上没有允许您就地修改字符串的函数。如果有,那么这些更改将在函数外部可见。

这是因为该类的赋值运算符是如何实现的

myList = new List<string>() { "new list" };
考虑以下代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


class Program
{
    static void Main(string[] args)
    {
        List<string> list = new List<string>();
        list.Add("1");
        String text = "text";

        //Change Something In anotherText
        String anotherString = text;
        anotherString = "another String Changed";
        Console.WriteLine(text);

        //Change Something In anotherList
        List<string> anotherList = list;
        anotherList.Add("added in another List");

        foreach (var i in list)
        {
            Console.WriteLine(i);
        }

    }
}
我们实际上是在创建一个新的String对象,此时的值等于text,这是由于String类中的赋值运算符重载造成的。但是,当我们写作的时候

String anotherString = text;
List<string> anotherList = list;
我们只是在创建原始列表对象的另一个引用。请注意,此赋值中没有创建新对象,两个引用都引用同一对象


方法参数还使用赋值操作来初始化参数

查看文档,如果您执行myList=new List,然后检查它,您将看到与其他人所说的相同的效果,这是“按值传递”与“按引用传递”的问题。@Sotirios等人:发布的重复问题不是一个好问题:这里有趣的一点与字符串有关,而不是一般的按引用传递。这是一个更好的问题:@pb2q我看不出有什么不同。无论是字符串还是任何其他类型,行为都是相同的。它是赋值与去引用和方法调用。类型的不变性与此无关。@SotiriosDelimanolis抱歉:我读这个问题太匆忙了。这只是一个试图更改传递值引用的问题。我收回我的评论:你原来的dup很好。我很烦你在回复中重复同样的内容。你的答案中的所有内容都在那里。副本不是关于问题,而是关于提供问题答案的内容。这就是为什么重复标签说明这个问题在这里已经有了答案。这个问题被标记为java,而这个代码是C。这个问题实际上不是关于通过引用传递与通过值传递,而是分配引用与修改值之间的区别。同样,这不是关于问题,而是关于答案。这里的答案解释了参考值、对象和变量之间的区别,以及改变对象和重新指定变量之间的区别。我相信在不涉及out和ref的情况下,C在引用类型上的行为与Java相同。你的回答很好。我只是觉得没有必要。虽然相同的信息可能包含在链接的q+a中,但它也包含在MSDN和javadocs中。我回答的目的是将信息整理成对所问特定问题的回答。这不仅仅是关于答案,也是关于这个问题,我认为相关问题与这个问题还不够接近。