2016-03-29 72 views
3
string s1 = "abc"; 
string s2 = s1; 
s2 = "123"; 
Debug.Log(s1 + ":" + s2); 

结果是ABC:123字符串是引用类型,但为什么它的值类型的工作时,它的分配更新

那么,为什么S1未更新为123 S1和S2包含相同的参考并且如果一个变量更新它然后第二个会自动更新。

+0

字符串是不可变 –

+0

@取消幸运问题的标题是相同的,但问题内容是不同的。我已经检查过 –

+0

字符串是不可变的(或者它们是引用或值类型)对于这个问题并不重要。这个问题是关于变量的,而不是关于它们的内容。 – Jcl

回答

3

这是对参考文献使用的常见误解。

s1是一个引用类型,但其内容是一个值。您可以认为所有变量都是值类型,但编译器处理它们的方式因值或引用类型而异。

string s1 = "abc"; 

S1等于其中“ABC”的地址被存储,让我们说0x0000AAAA

string s2 = s1; 

S2指向相同的地址S1因此,它的值是相同的S1。两者都有价值0x000AAAA

s2 = "123"; 

字符串是不可变的,这意味着你不能修改字符串,任何时候你分配一个新值或修改,您要创建一个新的字符串在内存中的其他地方,而前一个准备好了GC ,如果需要的话(实际上不是这样)。此时,s1的值仍然为0x0000AAAA,而s2的值为0X0000BBBB。

Debug.Log(s1 + ":" + s2); 

由于两个点在不同的内容,他们打印不同的结果。

它只是一个引用类型,因为变量中包含的值并不是要按原样使用,而是要将指针发送到存储实际对象的内存中的地址位置。

除非使用out/ref(C++中的&),则暗示将使用该变量的值(地址),最有可能作为参数。

请注意,此行为与任何对象相同,不仅是字符串。

Dog dogA = new Dog(); 
Dog dogB = dogA; 
dogA.name = "Wolfie"; // Affect both since we are dereferencing 
dogA = new Dog(); // dogA is new object, dogB is still Wolfie 

编辑:OP需要解释关于ref/out。

当你想改变一个对象,你会觉得以下几点:

void ChangeObject(GameObject objParam) 
{ 
    objParam = new GameObject("Eve"); 
} 

void Start(){ 
    GameObject obj = new GameObject("Adam"); 
    ChangeObject(obj); 
    Debug.Log(obj.name); // Adam...hold on should be Eve (??!!) 
} 

的ChangeObject得到一个GameObejct作为参数,编译器拷贝OBJ(00000AAAA)包含到objParam价值,它使一个副本它和现在都具有相同的价值。

在该方法中,objParam被赋予一个新的值,并且与方法外部的obj没有更多的关联。 objParam是该方法的局部,并在完成时被移除(游戏对象仍然在场景中,但引用丢失)。

如果您希望在更改方法中的obj:

void ChangeObject(ref GameObject objParam) 
{ 
    objParam = new GameObject("Eve"); 
} 

void Start(){ 
    GameObject obj = new GameObject("Adam"); 
    ChangeObject(ref obj); 
    Debug.Log(obj.name); // Yeah it is Eve !!! 
} 

这一次,它不是传递obj的价值,但obj的地址。所以obj可能包含0x0000AAAA,但它自己的地址是0x0000AABB,那么objParam的值现在是0x0000AABB,并且更改objParam意味着更改存储在0x0000AABB处的值。

out和ref的工作方式是一样的,只有out需要在方法内赋值,而ref可以离开方法而不影响给定的参数。

+0

你能否定义它更多'除非你使用/ ref(&在C++中),那么它暗示着变量的值将被使用(地址),很可能是一个参数。 –

0

因为变量不是对象。变量是引用对象

当你做s2 = "123",你重新分配参考变量s2(而不是它指出对象),为不同的对象(与值123

是的,string是不可改变的类型string的对象(如其他人士),但实际上不是对这个问题的罪魁祸首。这发生在可变和不可变类型以及值和引用类型。关键的区别在于,您正在修改变量指向的引用(内存地址),因此您不会更改该内存地址的内容。

用值类型:

int i1 = 0; 
int i2 = i1; 
i2 = 2; 
Debug.Log(i1.ToString() + ":" + i2.ToString()); 

会记录:0:2

并与参考类型:

public class MyClass { 
    private string _cont; 
    public MyClass(string cont) { _cont = cont; } 
    public override string ToString() { return _cont; } 
} 

MyClass c1 = new MyClass("abc"); 
MyClass c2 = c1; 
c2 = new MyClass("123"); 
Debug.Log(c1.ToString() + ":" + c2.ToString()); 

也将登录abc:123

只有两种方式在C#中更改内存地址的实际内容的变量指向:一是用unsafe指针(它们有自己的语法),另一个是将该变量作为refout参数传递给方法(并且需要明确完成)。

1

字符串是不可变的。 当您分配string s1 = "abc"时,您正在将由字符串文字abc创建的新对象引用分配给s1的引用。
因此,当您指定s2 = "123";时,s2将引用由字符串文字"123"创建的新对象。
希望这有助于!

1

通过将一个字符串文字赋值给一个String变量,您实际上是实例化一个新的字符串对象并将其分配给现有的字符串对象。即

如果我们声明并初始化s1如下;

string s1 = "abc"; 

实际上正在发生的事情是,我们正在创造一个新的字符串对象abc并分配给s1这是类似的:假设Foo是一类]。

Foo fooObj= new Foo(); 
fooObj= new Foo(); // this will be a new instant 

还有一点需要澄清; new Foo();将在内部创建一个对象,并分配给fooObj我们无法改变的new Foo();的价值,因为它在内部创建,但我们可以处理fooObj

+0

很好的回答方式,但几乎相同的事情已经由fafse说。谢谢 –

相关问题