值类型和引用类型的区别
C#基础:值类型和引用类型的区别

C#基础:值类型和引⽤类型的区别⼀、值类型和引⽤类型的区别.NET的类型可以分为两类:值类型和引⽤类型。
这两种类型各有特点,即使它们都继承⾃System.Object,并且有装箱和拆箱等操作确保两种类型可以⽅便地交互,但是理解值类型和引⽤类型将有助于程序员编写出⾼效的代码,相反的,在不理解值类型和引⽤类型的情况下,程序员很容易编写出可以正确执⾏但性能较差的代码。
所有.NET的类型都可以分为两类:值类型和引⽤类型。
最简单也最明确的⼀个区分标准是:所有的值类型都继承⾃System.ValueType(System.ValueType继承⾃System.Object),也就是说,所有继承⾃System.ValueType的类型都是值类型,⽽其他类型都是引⽤类型。
常⽤的值类型包括结构、枚举、整数型、浮点型、布尔型等,⽽在C#中所有以class关键字定义的类型都是引⽤类型。
1、赋值时的区别引⽤类型和值类型最显著的⼀个区别在于变量的赋值问题。
值类型的变量将直接获得⼀个真实的数据副本,⽽对引⽤类型的赋值仅仅是把对象的引⽤赋给变量,这样就可能导致多个变量引⽤到⼀个实际对象实例上。
来看下⾯⼀个简单的⽰例:⾸先为了测试建⽴⼀个简单的引⽤类型和⼀个简单的值类型。
然后在Main⽅法中,测试对值类型和引⽤类型对象进⾏赋值的不同结果,代码如下:using System;namespace ConsoleApp1{///<summary>///⼀个简单的引⽤类型///</summary>public class Ref{public int iValue { get; set; }public Ref(int i){iValue = i;}public override string ToString(){return $"iValue的值为:{iValue.ToString()}";}}///<summary>///⼀个简单的值类型///</summary>public struct Val{public int Value { get; set; }public Val(int i){Value = i;}public override string ToString(){return $"Value的值为:{Value.ToString()}";}}class Program{static void Main(string[] args){// 测试引⽤类型的赋值Ref ref1 = new Ref(1);Ref ref2 = ref1;// 赋值ref2.iValue = 2;// 测试值类型的赋值Val val1 = new Val(1);Val val2 = val1;val2.Value = 2;//输出Console.WriteLine($"ref1:{ref1}");Console.WriteLine($"ref2:{ref2}");Console.WriteLine($"val1:{val1}");Console.WriteLine($"val2:{val2}");Console.ReadKey();}}}简单分析上⾯的代码,程序定义了⼀个引⽤类型Ref和⼀个值类型Val,两者的内容⼏乎完全相同。
值类型和引用类型的区别

CLS是CTS的一个子集。这就意味着一种语言特征可能符合CTS标准,但又超出CLS的范畴。例如:C#支持无符号数字类型,该特征能通过CTS的测试,但CLS却仅仅识别符号数字类型。因此,如果用户在一个组件中使用C#的无符号类型,就可能不能与不使用无符号类型的语言(如)设计的.NET组件实现互操作。这里用的是“可能不”,而不是“不可能”,因为这一问题实际依赖于对non-CLS-compliant项的可见性。事实上,CLS规则只适用于或部分适用于那些与其他组件存在联系的组件中的类型。实际上,用户能够安全实现含私有组件的项目,而该组件使用了用户所选择使用的.NET语言的全部功能,且无需遵守CLS的规范。另一方面,如果用户需要.NET语言的互操作性,那么用户的组件中的公共项必须完全符合CLS规范。让我们来看下面的C#代码:
{
return A;
}
}
最后一个C是公共语言运行库Common Language Runtime(CLR)。简单地说,CLR是CTS的实现,也就是说,CLR是应用程序的执行引擎和功能齐全的类库,该类库严格按照CTS规范实现。作为程序执行引擎,CLR负责安全地载入和运行用户程序代码,包括对不用对象的垃圾回收和安全检查。在CLR监控之下运行的代码,称为托管代码(managed code)。作为类库,CLR提供上百个可用的有用类型,而这些类型可通过继承进行扩展。对于文件I/O、创建对话框、启动线程等类型—— 基本上能使用Windows API来完成的操作,都可由其完成。
6、典型的值类型为:struct,enum以及大量的内置值类型;而能称为类的都可以说是引用类型。
7、值类型的内存不由GC(垃圾回收,Gabage Collection)控制,作用域结束时,值类型会自行释放,减少了托管堆的压力,因此具有性能上的优势。例如,通常struct比class更高效;而引用类型的内存回收,由GC来完成,微软甚至建议用户最好不要自行释放内存。
值类型与引用类型区别

解析:CLR支持两种类型:值类型和引用类型。
用Jeffrey Richter(《CLR via C#》作者)的话来说,“不理解引用类型和值类型区别的程序员将会把代码引入诡异的陷阱和诸多性能问题”。
这就要求我们正确理解和使用值类型和引用类型。
值类型包括C#的基本类型(用关键字int、char、float等来声明),结构(用struct关键字声明的类型),枚举(用enum关键字声明的类型);而引用类型包括类(用class关键字声明的类型)和委托(用delegate关键字声明的特殊类)。
C#中的每一种类型要么是值类型,要么是引用类型。
所以每个对象要么是值类型的实例,要么是引用类型的实例。
值类型的实例通常是在线程栈上分配的(静态分配),但是在某些情形下可以存储在堆中。
引用类型的对象总是在进程堆中分配(动态分配)。
(1)在C#中,变量是值还是引用仅取决于其基本数据类型。
C#的基本数据类型都与平台无关。
C#的预定义类型并没有内置于语言中,而是内置于.NET Framework中。
.NET使用通用类型系统(CTS)定义可以在中间语言(IL)中使用的预定义数据类型。
C#中所有的数据类型都是对象。
它们可以有方法、属性等。
例如,在C#中声明一个int变量时,声明实际上是CTS (通用类型系统)中System.Int32的一个实例:int i; i = 1; string s; s = i.ToString(); 下图说明了CTS中各个类型是如何相关的。
(2)System.Object和System.ValueType。
引用类型和值类型都继承自System.Object类。
不同的是,几乎所有的引用类型都直接从System.Object继承,而值类型则继承其子类,即直接继承System.ValueType。
作为所有类型的基类,System.Object提供了一组方法,这些方法在所有类型中都能找到。
其中包含toString 方法及clone等方法。
值类型和引用类型的区别

值类型和引⽤类型的区别c#⽀持两种类型:值类型(Value Types)和引⽤类型(Reference Types),值类型包括简单类型(如:char、int和float等等)、枚举类型(Enum Types)和结构类型(Struct Types)、引⽤类型包括类类型、接⼝类型、委托类型和数组类型。
值类型与引⽤类型的不同点在于:值类型的变量直接包含它们的数据,⽽引⽤类型的变量则把引⽤存储到对象中。
引⽤类型的两个变量可以引⽤同⼀个对象。
这样,对⼀个变量的操作就可能影响另⼀个变量所引⽤的对象。
值类型的每⼀个变量都具有它们⾃⼰的数据拷贝,因此对⼀个变量的操作不可能影响到另⼀个变量。
using System;using System.Collections.Generic;using System.Text;namespace ConsoleApplication1{class Person{public int Blood = 10;}class Program{public static void Add(int x){x += 10;Console.WriteLine("值类型当参数被传递并修改之后:"+x);}public static void Add(Person person){person.Blood += 10;Console.WriteLine("引⽤类型当参数被传递并修改之后:" + person.Blood);}static void Main(string[] args){//值类型变量int i = 10;Console.WriteLine("i的原值:" + i);Add(i);Console.WriteLine("但是i的值并没有因为函数的修改⽽修改:" + i);//引⽤类型变量Person person = new Person();Console.WriteLine("Blood的原值:" + person.Blood);Add(person);Console.WriteLine("但是Blood的值因为函数的修改⽽修改:" + person.Blood);//值类型和引⽤类型的区别,就在于当函数参数传递的时候.//值类型是把⾃⼰的值复制⼀份传递给别的函数操作.⽆论复制的值怎么被改变.其⾃⾝的值是不会改变的//⽽引⽤类型是把⾃⼰的内存地址传递给别的函数操作.操作的就是引⽤类型值的本⾝.所以值被函数改变了.//这就是传值和传址的区别Console.ReadLine();}}}using System;using System.Collections.Generic;using System.Text;namespace ConsoleApplication1{class Person{public int Blood = 10;}class Program{public static void Add(int x){x += 10;Console.WriteLine("值类型当参数被传递并修改之后:"+x);}public static void Add(Person person){person.Blood += 10;Console.WriteLine("引⽤类型当参数被传递并修改之后:" + person.Blood);}static void Main(string[] args){//值类型变量int i = 10;Console.WriteLine("i的原值:" + i);Add(i);Console.WriteLine("但是i的值并没有因为函数的修改⽽修改:" + i);//引⽤类型变量Person person = new Person();Console.WriteLine("Blood的原值:" + person.Blood);Add(person);Console.WriteLine("但是Blood的值因为函数的修改⽽修改:" + person.Blood);//值类型和引⽤类型的区别,就在于当函数参数传递的时候.//值类型是把⾃⼰的值复制⼀份传递给别的函数操作.⽆论复制的值怎么被改变.其⾃⾝的值是不会改变的//⽽引⽤类型是把⾃⼰的内存地址传递给别的函数操作.操作的就是引⽤类型值的本⾝.所以值被函数改变了.//这就是传值和传址的区别Console.ReadLine();}}}⼀个具有值类型(值类型(value type)的数据存放在栈内的⼀个变量中。
2018年必看的VR面试题

2018年必看的VR面试题各大公司、企业都在纷纷布局VR行业,而近期不断出现的VR影视、VR 教育、VR医疗,也让很多人都看到了VR市场的火爆,越来越多的人想从事这个前景一片大好的行业。
2018年必看的VR面试题在此分享给大家。
1.请简述值类型与引用类型的区别答:区别:1)值类型存储在内存栈中,引用类型数据存储在内存堆中,而内存单元中存放的是堆中存放的地址。
2)值类型存取快,引用类型存取慢。
3)值类型表示实际数据,引用类型表示指向存储在内存堆中的数据的指针和引用。
4)栈的内存是自动释放的,堆内存是.NET中会由GC来自动释放。
5)值类型继承自System.ValueType,引用类型继承自System.Object。
2.C#中所有引用类型的基类是什么答:引用类型的基类是System.Object值类型的基类是System.ValueType 同时,值类型也隐式继承自System.Object3.请简述ArrayList和List的主要区别答:ArrayList存在不安全类型‘(ArrayList会把所有插入其中的数据都当做Object来处理)装箱拆箱的操作(费时)List是接口,ArrayList是一个实现了该接口的类,可以被实例化。
4.请简述GC(垃圾回收)产生的原因,并描述如何避免?答:产生原因:GC回收堆上的内存避免:1)减少new产生对象的次数2)使用公用的对象(静态成员)3)将String换为StringBuilder5.请描述Interface与抽象类之间的不同答:抽象类表示该类中可能已经有一些方法的具体定义,但接口就是公公只能定义各个方法的界面,不能具体的实现代码在成员方法中。
类是子类用来继承的,当父类已经有实际功能的方法时该方法在子类中可以不必实现,直接引用父类的方法,子类也可以重写该父类的方法。
实现接口的时候必须要实现接口中所有的方法,不能遗漏任何一个。
8.请简述关键字Sealed用在类声明和函数声明时的作用答:类声明时加Sealed可防止其他类继承此类,在方法中声明则可防止派生类重写此方法。
js值类型和引用类型

js值类型和引⽤类型JavaScript值类型和引⽤类型有哪些(1)值类型:数值、布尔值、null、undefined。
(2)引⽤类型:对象、数组、函数。
四、如何理解值类型和引⽤类型及举例我们可以⽤“连锁店”和“连锁店钥匙”来理解,不知道以下⽐喻合不合适,^-^。
(1)值类型理解:变量的交换等于在⼀个新的地⽅按照连锁店的规范标准(统⼀店⾯理解为相同的变量内容)新开⼀个分店,这样新开的店与其它旧店互不相关、各⾃运营。
【值类型例⼦】复制代码代码如下:function chainStore(){var store1='Nike China';var store2=store1;store1='Nike U.S.A.';alert(store2); //Nike China}chainStore();//把⼀个值类型(也可以叫基本类型)store2传递给另⼀个变量(赋值)时,其实是分配了⼀块新的内存空间,因此改变store1的值对store2没有任何影响,因为它不像引⽤类型,变量的交换其实是交换了指像同⼀个内容的地址。
(2)引⽤类型理解:变量的交换等于把现有⼀间店的钥匙(变量引⽤地址)复制⼀把给了另外⼀个⽼板,此时两个⽼板同时管理⼀间店,两个⽼板的⾏为都有可能对⼀间店的运营造成影响。
【引⽤类型例⼦】复制代码代码如下:function chainStore(){var store1=['Nike China'];var store2=store1;alert(store2[0]); //Nike Chinastore1[0]='Nike U.S.A.';alert(store2[0]); //Nike U.S.A.}chainStore();//在上⾯的代码中,store2只进⾏了⼀次赋值,理论上它的值已定,但后⾯通过改写store1的值,发现store2的值也发⽣了改变,这正是引⽤类型的特征,也是我们要注意的地⽅。
c#基础系列之值类型和引用类型的深入理解

c#基础系列之值类型和引⽤类型的深⼊理解前⾔不知不觉已经踏⼊坑已10余年之多,对于c#多多少少有⼀点⾃⼰的认识,写出来渴求同类抨击,对⾃⼰也算是个⼗年之痒的⼀个总结。
C#把数据类型分为值类型和引⽤类型1.1:从概念上来看,其区别是值类型直接存储值,⽽引⽤类型存储对值的引⽤。
1.2:这两种类型在内存的不同地⽅,值类型存储在堆栈中,⽽引⽤类型存储在托管对上。
存储位置的不同会有不同的影响。
下⾯话不多说了,来⼀起看看详细的介绍吧基本概念CLR⽀持两种类型:值类型和引⽤类型。
⾯试过很多5年左右的同学,有很多连值类型和引⽤类型的基本概念都回答不上来,难道现在的c#开发⼈员基础这么弱了吗?还是⼤家都不重视基础呢?这个随便找⼀篇博客都可以基础⼊门的。
引⽤类型哪些类型是引⽤类型呢?其实⼀个可以称为”类“的类型都是引⽤类型。
引⽤类型总是从托管堆上分配的,常⽤的语法就是New XX(). C#的new 操作符会返回对象的指针 - 也就是指向对象数据的内存地址的⼀个引⽤。
引⽤类型的传递其实传递的是对象的指针(string类型⽐较特殊),所以在特定的场景下性能是⾼于值类型的。
⼀个引⽤类型在创建时默认为null,也就是说当前变量不指向⼀个有效的对象,也就是我们常遇到的异常“未将对象引⽤设置到对象的实例”。
值类型因为引⽤类型变量都需要进⾏⼀次堆内存的分配,这会给GC造成很⼤的压⼒,所以CLR提供了轻量级类型“值类型”。
值类型⼀般在线程栈上分配。
(注意:值类型可以嵌⼊⼀个引⽤对象中)⼀个值类型变量其实就包含了值类型实例的值,所以它没有引⽤类型的指针(⼤家猜想值类型需不需要类型对象指针呢?)相同点和不同点相同点值类型和引⽤类型都是System.Object的⼦类值类型和引⽤类型都可以继承接⼝。
(很多⼈都认为值类型不能继承接⼝)interface Itest{void test();}struct TestStruct : Itest{public void test(){throw new NotImplementedException();}}不同点值类型分配在堆栈上,引⽤类型是在托管堆上分配的。
漫谈值类型和引用类型

漫谈值类型和引用类型一.前言从这个简单程序的输出结果,你想到了什么?是不是与你心中想的结果不一致?是不是觉得输出的结果应该为:i is 1,o is 8,o2 is 8二.程序执行前图 2我们都知道,每一个方法在执行前,操作系统会给方法内每个变量分配内存空间。
从图2中就可以看出,在执行前各变量(i,o,o2)已分配了内存,且各自都有初始值。
从图中,可以发现变量i和变量o,o2有些许不同。
变量i在内存中存储的值和程序中的值是一样的,都是0;变量o,o2在内存中存储的值和程序中的值不一样,内存中存储的值是一个地址(0x00000000),程序中的值是null,那变量o,o2的null值存储在哪呢?为什么变量i和变量o,o2会有如此大的不同呢?我们都知道,C#有两大类型:值类类型和引用类型。
图2中int属于值类型,object属于引用类型。
接下来,介绍一下值类型和引用类型:1.值类型的值存储在内存栈上,引用类型的值存储在内存堆中。
园中有很多博文这么描述,我用程序验证了一下全局的值类型变量的值,静态的值类型变量的值,引用类型实例中值类型成员的值,如下图3图 3从图中,可以看出变量(j,o,seg,st)的值应该是在同一个存储区域中,而变量(gi)是在另外一个存储区域中。
引用类型Student的成员Age的地址还未分配。
所以说值类型的值存储在内存栈上是不准确的。
查找了一些资料,内存格局分为四个区:1)全局数据区:存放全局变量,静态变量,常量的值2)代码区:存放程序代码3)栈区:存放为运行而分配的局部变量,参数等4)堆区:自由存储区。
更为准确的说,方法体内的值类型变量的值存储在内存栈上,引用类型变量的值存储在内存堆上。
由于对象实例是引用类型变量的值,而对象实例成员只是对象实例的一部分,所以其随对象实例整个存储在内存堆上。
或许眼尖的园友发现了,上面那句话还是不对,结构体StructEg 的引用类型成员Name的数据就没有存储在内存栈上。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
值类型和引用类型的区别[转]似乎“值类型和引用类型的区别”是今年面试的流行趋势,我已然是连续三次(目前总共也就三次)面试第一个问题就遇到这个了,这是多大的概率啊,100%,哈哈,我该买彩票去!言归正传,咱还是先来探讨探讨这二者之间有什么区别吧。
记得有一次电话面试中,我直接跟面试官说:“值类型是现金,引用类型是存折”,后来想想当时说这话虽是有点儿冲动地脱口而出,但也没什么不妥。
我这人不善于背理论的教条,喜欢把书本上那些生硬的话跟现实生活中常见的事物联系起来理解和记忆。
直白点儿说:值类型就是现金,要用直接用;引用类型是存折,要用还得先去银行取现。
声明一个值类型变量,编译器会在栈上分配一个空间,这个空间对应着该值类型变量,空间里存储的就是该变量的值。
引用类型的实例分配在堆上,新建一个引用类型实例,得到的变量值对应的是该实例的内存分配地址,这就像您的银行账号一样。
具体哪些类型是值类型哪些是引用类型,大家翻翻书,背一背就好了,不过我想,做过一段时间的开发,即使您背不了书上教条的定义,也不会把值类型和引用类型搞混的。
接下来,还是老规矩,咱看码说话吧。
1:public class Person2: {3:public string Name { get; set; }4:public int Age { get; set; }5: }6:7:public static class ReferenceAndValue8: {9:public static void Demonstration()10: {11: Person zerocool = new Person { Name = "ZeroCool", Age = 25 };12: Person anders = new Person { Name = "Anders", Age = 47 };13:14:int age = zerocool.Age;15: zerocool.Age = 22;16:17: Person guru = anders;18: = "Anders Hejlsberg";19:20: Console.WriteLine("zerocool's age:\t{0}", zerocool.Age);21: Console.WriteLine("age's value:\t{0}", age);22: Console.WriteLine("anders' name:\t{0}", );23: Console.WriteLine("guru' name:\t{0}", );24: }25: }上面这段代码,我们首先创建了一个Person类,包含了Name和Age两个属性,毋庸置疑,Person 类是引用类型,Name也是,因为它是string类型的(但string是很特殊的引用类型,后面将专门有一篇文章来讨论),但Age则是值类型。
接下来我们来看看Demonstration方法,其中演示的就是值类型跟引用类型的区别。
首先,我们声明了两个Person类的实例对象,zerocool和anders,前面提到过,这两个对象都被分配在堆上,而zerocool和anders本身其实只是对象所在内存区域的起始地址引用,换句话说就是指向这里的指针。
我们声明对象实例时也顺便分别进行了初始化,首先我们看,zerocool 对象的值类型成员,我们赋值为25(对,我今年25岁),anders(待会儿你们就知道是谁了)的Name属性,我们赋值为“Anders”。
齐活儿,接下来看我们怎么干吧。
我们声明一个值类型变量age,直接在初始化时把zerocool的Age值赋给它,显然,age的值就是25了。
但这个时候zerocool不高兴了,他想装嫩,私自把自己的年龄改成22岁,刚够法定结婚年龄。
然后我们又声明了一个引用类型的guy对象,初始化时就把anders赋给它,然后anders露出庐山真面目了,他的名字叫“Anders Hejlsberg”(在此向C#之父致敬)。
接下来我们来分别答应出这几个变量的值,看看有什么差别。
你可能要觉得奇怪(你要不觉得奇怪,也就不用再接着往下看了),为什么我们改了zerocool.Age 的值,age没跟着变,改了的值,却跟着变了呢?这就是值类型和引用类型的区别。
我们声明age值类型变量,并将zerocool.Age赋给它,编译器在栈上分配了一块空间,然后把zerocool.Age的值填进去,仅此而已,二者并无任何牵连,就像复印机一样,只是把zerocool.Age的值拷贝给age了。
而引用类型不一样,我们在声明guy的时候把anders 赋给它,前面说过,引用类型包含的是只想堆上数据区域地址的引用,其实就是把anders的引用也赋给guy了,因此这二者从此指向了同一块内存区域,既然是指向同一块区域,那么甭管谁动了里面的“奶酪”,另一个变现出来的结果也会跟着变,就像信用卡跟亲情卡一样,用亲情卡取了钱,与之关联的信用卡账上也会跟着发生变化。
一提到钱,估计大家伙儿印象就深了些吧,呵呵!另外,性能上也会有区别的。
既然一个是直接操作内存,另一个则多一步先解析引用地址,那么显然很多时候值类型会减小系统性能开销。
但“很多时候”不代表“所有时候”,有些时候还得量力而为,例如需要大量进行函数参数传递或返回的时候,老是这样进行字段拷贝,其实反而会降低应用程序性能。
另外,如果实例会被频繁地用于Hashtable或者ArrayList之类的集合中,这些类会对其中的值类型变量进行装箱操作,这也会导致额外的内存分配和内存拷贝操作,从应用程序性能方面来看,其实也不划算。
哦对了,上面提到了一个概念,装箱。
那么什么是装箱呢?其实装箱就是值类型到引用类型的转化过程。
将一个值类型变量装箱成一个引用类型变量,首先会在托管堆上为新的引用类型变量分配内存空间,然后将值类型变量拷贝到托管堆上新分配的对象内存中,最后返回新分配的对象内存地址。
装箱操作是可逆的,所以还有拆箱操作。
拆箱操作获取只想对象中包含值类型部分的指针,然后由程序员手动将其对应的值拷贝给值类型变量。
接下来我们来看看典型的装箱和拆箱操作。
1:public static class BoxingAndUnboxing2: {3:public static void Demonstration()4: {5:int ageInt = new int();6:7:// Boxing operation.8:object ageObject = ageInt;9:10://ageObject = null;11:12:// Unboxing operation.13: ageInt = (int)ageObject;14:15: Console.WriteLine(ageInt);16: }17: }在该方法中,我们首先声明了一个值类型变量ageInt,但并未给它赋值,接着声明了一个典型的引用类型变量ageObject,并把ageInt赋给它,这里就进行了一次装箱操作。
编译器现在托管堆上分配一块内存空间(空间大小为对象中包含的值类型变量所占空间总和外加一个方法表指针和一个SyncBlockIndex),然后把ageInt拷贝到这个空间中,再返回该空间的引用地址。
接下来第13行则是拆箱操作,编译器获取到ageObject对象中值类型变量的指针,然后将其值拷贝给值类型变量。
如果你把第10行注释掉的代码打开(这是通俗说法,其实就是取消注释),那么第13行就会抛出System.NullReferenceException异常,要说问什么,这又会牵扯出值类型跟引用类型另一个大的不同。
看见了吧,声明ageInt时并没有赋值,如果关掉第10行代码,程序不会报错,最后打印出个0,这说明在声明值类型变量时,如果没有初始化赋值,编译器会自动将其赋值为0,既然值类型没有引用,那么它就不可能为空。
引用类型不一样,它可以为空引用,一张过期作废的银行卡是可以存在。
而如果将一个空的对象拆箱,编译器上哪儿去找它里面的值类型变量的指针呢?所以这也是拆箱操作需要注意的地方。
最后,我们在把值类型和引用类型之间其它一些明显区别大致罗列如下,以便大家能顺利通过面试第一问。
∙所有值类型都继承自System.ValueType,但是ValueType没有附加System.Object包含之外其它任何方法,不过它倒是改写了Equals和GetHashCode两个方法。
引用类型变量的Equals比较的是二者的引用地址而不是内部的值,值类型变量的Equals方法比较的是二者的值而不是……哦对了,值类型压根儿没有引用地址;∙值类型不能作为其它任何类型的基类型,因此不能向值类型中增加任何新的虚方法,更不该有任何抽象方法,所有的方法都是sealed的(不可重写);∙未装箱的值类型分配在栈上而不是堆上,而栈又不是GC的地盘儿,因此GC根本不过问值类型变量的死活,一旦值类型变量的作用范围一过,它所占的内存空间就立即被回收掉,不劳GC亲自动手。
以上罗列的都是值类型和引用类型之间的主要区别,文码并茂,相信应该给你留下比较深刻的印象,虽不够深,但愿能起到抛砖引玉的作用。
如果去面SDE职位,估计这深度就差不多了,我这文章不是面向那些要去面Senior SDE甚至Dev Lead的正神,咱这儿庙小,嘿嘿!。