600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > C# string 特殊的引用类型

C# string 特殊的引用类型

时间:2023-05-14 05:53:06

相关推荐

C# string 特殊的引用类型

.Net 框架程序设计(修订版)中有这样一段描述:String类型直接继承自Object,这使得它成为一个引用类型,也就是说线程上的堆栈上不会驻留有任何字符串。(译注:注意这里的“直接继承”。直接继承自Object的类型一定是引用类型,因为所有的值类型都继承自System.ValueType。值得指出的是System.ValueType却是一个引用类型)。

一:

string str1 = "string";

string str2 = "string"; Console.WriteLine(string.ReferenceEquals(str1, str2));

既然String类型是引用类型,那么代码一输出的应该是False,然而事实上代码一输出时的是True。

其实这是String类型的自动优化功能。str1,str2引用同一对象,节省内存,并不会为str2单独开辟内存空间。CLR使用了一种叫字符串驻留的技术,当CLR初始化时,会创建一个内部的散列表,其中的键为字符串,值为指向托管堆中字符串的引用。刚开始,散列表为空,JIT编译器编译方法时,会在散列表中查找每一个文本常量字符串,首先会查找"abc"字符串,并且因为没有找到,编译器会在托管堆中构造一个新的指向"abc"的String对象引用,然后将"abc"字符串和指向该对象的引用添加到散列表中。接着,在散列表中查找第二个"abc",这一次由于找到了该字符串,指向同一个String对象的引用会被保存在变量str2中,到此str1和str2指向了同一个引用,所以string.ReferenceEquals(str1, str2)就会返回true了。

str4的一个实例"abc"放在托管堆里,当str1,str2,str3的量也是“abc”时,CLR发现已经有同样的字符串已经存在在内存中,将"adc"放入拘留池里,而不是创建一个新的字符串。只是让str1,str2,str3指向str4的对象。

为了检验拘留池的实际效果。用“==”操作符比较字符串,另外使用Object.RefernceEqueals方法来比较字符串的地址。

Console.WriteLine(str4==str1);//true;(值是相同的)

Console.WriteLine(str4==str2);//true;

Console.WriteLine(RefernceEqueals(str4,str1));//false(地址不同)

str1,str2,str3内存地址和str4不同。

3

由于每次创建字符串都要检查拘留池,因此会影响性能,所有拘留池中是不存放动态创建的值。不过,为此提供一个String.Intern方法,以便有选择地向拘留池增加动态创建的字符串。如图2:新建

string c ="c";

string str5 ="ab"+c;//值为abc;

Console.WriteLine(RefernceEquals(str5,str1));//false.虽然值一样,但是地址不一样。str5系统重新分配有内存。

str5=string.Intern(str5);

Console.WriteLine(RefernceEquals(str5,str1));//true.

string.Intern方法在拘留池中搜索str5的值(abc);由于它已经在拘留池中,所以不用再增加。该方法返回已有对象Object的引用,并赋给str5,由于str5和str1指向相同的对象“abc”,所以最后一条语句为true。而str5所创建的对象会在下一次的垃圾收集时被释放并清除。

String.Intern方法使得字符串变量可以利用引用比较,只有字符串变量出现在多个比较中时才会用到。

另外,C#中是不允许用new操作符创建String对象的,编译器会报错。

二:

static void Main(string[] args) {

string str = "string"; Change(str); Console.WriteLine(str); } static void Change(string str) { str = "Changed"; }

方法传递的参数是原内容的拷贝,其过程如果用图可表示为:

语句str=”Changed”之前

语句str=”Changed”之后

这样可以看到原来String对象并未改变str=”Changed”只是创建一个新的String对象(其它引用类型是改变内存地址1指向的值),因此这个方法的参数需要加上ref或者out修饰符。因此这里也可以得出字符串具有恒等性,也就是说一个字符串一旦被创建,我们就不能再将其变长、变短、或者改变其中的任何字符。

MSDN上这样解释:字符串对象是不可变的,即它们一旦创建就无法更改。对字符串进行操作的方法实际上返回的是新的字符串对象。

string在另一种情况下的操作是具有值类型特征的:str1 == str2 ,仅仅是比较了值,而非地址(是MS重写了==运算符所致).

三:

String 对象是不可改变的。每次使用 System.String 类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间。在需要对字符串执行重复修改的情况下,与创建新的 String 对象相关的系统开销可能会非常昂贵。如果要修改字符串而不创建新的对象,则可以使用 System.Text.StringBuilder 类。例如,当在一个循环中将许多字符串连接在一起时,使用 StringBuilder 类可以提升性能。

下面看一个极简单的例子:

namespace TCP

{

public class Program

{ publicclassUser

{

privatestring_name;

privatestring_age;

publicUser(stringname,stringage)

{

_name=name;

_age=age;

}

publicstringname

{

get{return_name;}

set{_name=value;}

}

publicstringage

{

get{return_age;}

set{_age=value;}

}

} } publicstaticvoideditUser(Useruser,StringBuilderstr,stringcode)

{

code="";

str=str.Remove(0,1);

str.Append("E");

user.name="LEE";

user.age="10";

} staticvoidMain(string[]args)

{

stringcode="C#";

Useruser=newUser("Li","23");

StringBuilderstr=newStringBuilder();

str.Append("A");

editUser(user,str,code);

Console.WriteLine(code);

Console.WriteLine(str);

Console.WriteLine(user.name);

Console.WriteLine(user.age);

Console.ReadLine();

} }

上面代码输如下:

这样可以看到原来String对象并未改变str=”Changed”只是创建一个新的String对象(其它引用类型是改变内存地址1指向的值),因此这个方法的参数需要加上ref或者out修饰符。因此这里也可以得出字符串具有恒等性,也就是说一个字符串一旦被创建,我们就不能再将其变长、变短、或者改变其中的任何字符。

MSDN上这样解释:字符串对象是不可变的,即它们一旦创建就无法更改。对字符串进行操作的方法实际上返回的是新的字符串对象。

string在另一种情况下的操作是具有值类型特征的:str1 == str2 ,仅仅是比较了值,而非地址(是MS重写了==运算符所致).

三:

String 对象是不可改变的。每次使用 System.String 类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间。在需要对字符串执行重复修改的情况下,与创建新的 String 对象相关的系统开销可能会非常昂贵。如果要修改字符串而不创建新的对象,则可以使用 System.Text.StringBuilder 类。例如,当在一个循环中将许多字符串连接在一起时,使用 StringBuilder 类可以提升性能。

下面看一个极简单的例子:

namespace TCP

{

public class Program

{ publicclassUser

{

privatestring_name;

privatestring_age;

publicUser(stringname,stringage)

{

_name=name;

_age=age;

}

publicstringname

{

get{return_name;}

set{_name=value;}

}

publicstringage

{

get{return_age;}

set{_age=value;}

}

} } publicstaticvoideditUser(Useruser,StringBuilderstr,stringcode)

{

code="";

str=str.Remove(0,1);

str.Append("E");

user.name="LEE";

user.age="10";

} staticvoidMain(string[]args)

{

stringcode="C#";

Useruser=newUser("Li","23");

StringBuilderstr=newStringBuilder();

str.Append("A");

editUser(user,str,code);

Console.WriteLine(code);

Console.WriteLine(str);

Console.WriteLine(user.name);

Console.WriteLine(user.age);

Console.ReadLine();

} }

上面代码输如下:

从上面可以看到string类型的值并没有改变,StringBuilder与class的值都改变了。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。