基本 哪些属于引用类型 类(object,string),接口、数组、委托 引用类型分配在哪里 引用类型变量位于线程栈。引用类型实例分配在托管堆上。当引用类型实例的大小小于85000
类(object,string),接口、数组、委托
变量:
变量分配在线程栈上。
变量可以是值类型,也可以是引用类型。
当变量是引用类型时,包含了对对象的引用(内存地址),也叫做"对象引用"。
对象:
对类、接口、委托和数组等的一个抽象描述。
实例:
在堆上创建的对象,称为对象实例。
Object a = null;
Console.WriteLine(a.ToString());
运行报错"未将对象引用设置到对象实例"。
意思是,在线程栈上创建的变量a没有指向到堆上的对象实例。
GC会遍历所有托管堆上的对象,按照一定的递归遍历算法,对那些没有被引用的不可访问对象实施回收。
class Program
{
static void Main(string[] args)
{
Person p;
p = new Person(20);
}
}
public class Person
{
public int _age;
public Person(int age)
{
_age = age;
}
public Person()
{
}
}
另外,引用类型的值,比如这里的引用类型Person中的值_age也被分配在托管堆上。
线程栈上的2个变量引用同一个对象实例的内存地址,改变其中一个变量的值会影响到另外一个变量。
class Program
{
static void Main(string[] args)
{
Person p1 = new Person(20);
Person p2 = p1;
Console.WriteLine("没有改变时p2的年龄是:" + p2._age + "岁");
p1._age = 18;
Console.WriteLine("改变p1的值,p2的年龄也被改变了,现在是:" + p2._age + "岁,真好,年轻了!");
Console.ReadKey();
}
}
public class Person
{
public int _age;
public Person(int age)
{
_age = age;
}
public Person()
{
}
}
从应用角度体现了值类型语义,从内存角度实现为引用类型存储,位于托管堆。
可以看作是char的集合char[]
string str = "Hello";
以下错误
String str = new String("Hello");
因为System.String没有提供此构造函数
以下可以
Char[] cs = {'a', 'b','c'};
String strArr = new String(cs);
但很少使用这种方式。
是指字符串一经创建,就不可改变。
字符串一旦创建,在托管堆上分配一块连续的内存空间。
恒定性的好处:
对String对象的任意操作,不会改变原字符串。
操作字符串不会出现线程同步的问题。
成就了字符串驻留。
恒定性的不足:
因为恒定性,对字符串的任何操作,比如字符串比较,字符串链接,字符串格式化等都会创建新的字符串,这样造成内存与性能的双重损耗。如下:
public static void Main()
{
string str = "This is a test about immuntablility of string type.";
Console.WriteLine(str.Inseert(0,"Hi").Substring(19).ToUpper());
Console.WriteLine(str);
}
由于Insert,Substring,ToUpper这些方法,都会创建出新的临时字符串,而这些新的字符串不被其他代码引用的时候,就会被垃圾回收,造成性能上的损失。
恒定性的前提,String为密封类:
public sealed class String:IComparable, ICloneable,IConvertible,IComparable<string>,IEnumerable<char>,IEnumerable,IEquatable<string>
MSDN对于字符驻留的定义:公共语言运行库通过维护一个哈希表(Hash Table)来存放字符串,该表成为拘留池,也叫驻留池。
字符串驻留弥补了恒定性的不足:
对于相同的字符串,CLR不会不会为其分配内存空间,而是共享同一内存。
CLR内部维护了一个哈希表HashTable来管理其创建的大部分String对象。key是string本身,value是string对应的内存地址。
驻留的2个静态方法:
public static string Intern(string str);
当str位于作为key位于CLR的驻留池时,返回对str的引用,否则将str字符串添加到hash table中,作为key,并返回引用。
public static string IsInterned(string str);
当str位于作为key位于CLR的驻留池时,返回对str的引用,否则返回null引用,也不添加到hash table中。
可以跨应用程序域AppDomain而存在,驻留池在CLR加载时创建,分配在System Domain中,被进程所有AppDomain所共享,其生命周期不受GC控制。
static void Main(string[] args)
{
string strA = "ab";
string strB = "ab";
Console.WriteLine(ReferenceEquals(strA,strB));
string strC = "a";
string strD = strC + "b";
Console.WriteLine(ReferenceEquals(strA, strD));
strD = String.Intern(strD);
Console.WriteLine(ReferenceEquals(strA,strD));
Console.ReadKey();
}
返回:
true
false
true
分析:
static void Main(string[] args)
{
string s1 = "abc";
string s2 = "ab";
string s3 = s2 + "c";
Console.WriteLine(string.IsInterned(s3) ?? "null");
Console.WriteLine(ReferenceEquals(s1,s3));
Console.ReadKey();
}
返回:
abc
false
分析:
static void Main(string[] args)
{
string strA = "abcdef";
string strC = "abc";
string strD = strC + "def";
Console.WriteLine(ReferenceEquals(strA,strD));
string StrE = "abc" + "def";
Console.WriteLine(ReferenceEquals(strA,StrE));
Console.ReadKey();
}
返回:
False,
true
分析:
static void Main(string[] args)
{
string s = "abc";
//IsInterned()获取字符串变量的引用
Console.WriteLine(string.IsInterned(s) ?? "null");
Console.ReadKey();
}
返回
"abc"。
分析:通过string s = "abc"使得hash table中有abc这个key,当进行string.IsInterned(s)手动驻留判断的时候,发现有abc这个key,就把对应的引用地址返回。
class Program
{
static void Main(string[] args)
{
string s = "ab";
s += "c";
//IsInterned()获取字符串变量的引用
Console.WriteLine(string.IsInterned(s) ?? "null");
Console.ReadKey();
}
}
返回
null
分析:通过string s = "ab";使得hash table中有了ab这个key,s += "c"是动态拼接,不会把abc放到hashtable中,所以当通过string.IsInterned(s)手动驻留判断的时候,发现没有abc这个key,就返回null。
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对编程网的支持。如果你想了解更多相关内容请查看下面相关链接
--结束END--
本文标题: C#中的引用类型以及特殊引用类型详解
本文链接: https://lsjlt.com/news/171272.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0