为什么一次又一次地重新分配字符串对象?

时间:2017-05-23 22:10:04

标签: c#

不是string不可变吗?为什么以下示例中line可以file.ReadLine()一次又一次地重新分配?感谢。

int counter = 0;
string line;

// Read the file and display it line by line.
System.IO.StreamReader file = 
   new System.IO.StreamReader("c:\\test.txt");
while((line = file.ReadLine()) != null)
{
   Console.WriteLine (line);
   counter++;
}

file.Close();

// Suspend the screen.
Console.ReadLine();

4 个答案:

答案 0 :(得分:15)

  

不是字符串不可变吗?

是的,字符串是不可变的。

  

为什么可以一次又一次地重新分配以下示例中的行

line不是字符串。 line是一个变量,它引用一个字符串。变量称为变量,因为它们不同

这可能意味着这个事实是引用的属性。事实并非如此。

数字1是不可变的,对吗?无论你对1做什么,它都是1.如果你加10比1得到11,你没有改变 10或1. 10和1仍然是10和1.结果是11,一个全新的号码。

因此,如果数字是不可变的,那我为什么要说:

int x = 1;
x = x + 10;

?因为x不是号码x变量,其中包含数字变量可以变化

让我们想一想另一个例子。想想在现实生活中不可改变的事物。比方说,硬币的价值。如果你有一毛钱,你可以做任何事情让它值得多于或少于10美分仍然有一角硬币。角色是不可变的。假设你有一个抽屉,你只保留一枚硬币,今天它包含一角硬币。明天你从抽屉里取出一角硬币并放入四分之一。如果一角硬币不变,你是怎么做到的? 变量就像抽屉。您可以更改其内容,即使抽屉中的对象是不可变的。

最后,你问题的标题清楚地表明了你混淆的根本原因:

  

为什么一次又一次地重新分配字符串对象?

对象不是首先可以分配的内容。 可以分配变量,变量不是对象。变量是存储位置,可以包含

如果你被某本书教过,变量是一种对象 - 并且许多初学者书籍犯了这个错误 - 那么扔掉那本书并获得一本体面的书没有谎言ReadLine返回的字符串是对象。对该对象的引用是分配给变量。然后,该变量的对不可变对象的引用

C#中有两件看起来像变量但语义略有不同的东西。

首先,const本地或字段不是变量,因为常量不能改变。如果它们可以变化那么它们将是变量,而不是常量。如果你说

const string s = "Hello";

那么Hello不仅是不可变的,而且s也是如此。您应该只将const用于逻辑上一直不可变的。黄金的价格,银行的名称,姓氏,这些都可以改变。黄金的原子量,pi的价值,这些东西永远不会改变,所以它们可以是const。 C#只允许某些类型为const,并且只允许某些表达式初始化const

readonly字段位于const和变量之间。 readonly字段是构造函数或字段初始值设定项中的变量,从任何其他位置写入都是非法的。 C#在构造函数或字段初始值设定项之外的所有代码中将只读字段视为,而不是变量

答案 1 :(得分:2)

不可变变量可以重新分配但不能变异

在这个例子中:

string s1 = "hello";
string s2 = s1; 
string s1 = "goodbye";

符号s1重新分配到新的字符串对象"再见" ,而s2指的是同一个原始字符串(" hello"),因为该字符串从未变异

答案 2 :(得分:2)

你的变量' line'应该被认为是指向字符串的指针,而不是字符串。

字符串本身无法更改。例如你不能做

    long currentTime = System.currentTimeMillis();
    long fireTime = 10 * 60 * 1000;    
    Intent ucintent = new Intent(getApplicationContext(),TimeAlarmReceiver.class);
    ucintent.putExtra("isAlarm", true);

    PendingIntent mTimeSlot = PendingIntent.getBroadcast(getApplicationContext(), (int) requestCode, ucintent, PendingIntent.FLAG_ONE_SHOT);
    alarmManager.set(AlarmManager.RTC_WAKEUP,currentTime+ fireTime, mTimeSlot);

期望能够改变第五个字符。与你可以做的c对比

line[4] = 'a'

(无论如何大多数情况下)

答案 3 :(得分:1)

不可变并不意味着不能重新分配对象的引用,这意味着对象本身不能被改变(改变)。

您可以永久重新分配for,但无法自行更改任何字符串。

如果您将引用设为常量,则无法重新分配。