18.1.4 连锁推导法:为什么值类型不可以为null而引用类型可以为null呢?

简介:

连锁推导法:在一个证明过程中,或一个比较复杂的推理过程中,将前一个推理的结论作为后一个推理的前提,一步接一步地推导,直到把需要的结论推出来。

我们在前面的知识中了解到值类型存储在堆栈(Stack)中,而引用类型存储在托管堆(Heap)中,堆栈的工作方式是以先进后出原则先保证先分配内存的变量后释放,你可以想像的出,堆栈中的变量是从后向前释放,这样就保证了堆栈中先进后出的规则不与变量的生命周期起冲突。

你可以仔细的想一下关于结构化编程的一些规则,C#对变量的声明要求是先定义后使用,变量的生命周期是从其定义开始直到程序的控制离开该变量所在的{}。以下代码描述了这个我们非常熟悉的事实

static void Main(string[] args)

{

int k = 10;//k的生命周期开始了

for (int i = 0; i <= 10 - 1; i++)//i的生命周期开始了

{

int m = k + i;//m的生命周期开始了

for (int j = i; j <= 10 - 1; j++)//j的生命周期开始了

{

int n = j * i;//n的生命周期开始了

//n的生命周期结束了

}//j的生命周期结束了

//m的生命周期结束了

}//i的生命周期结束了

//k的生命周期结束了

}

下面的图描述了这些变量的生命周期和堆栈的存储

同时我们在C#的编程中可以发现一个非常有趣的现象,即我们不能将值类型设置为null,但可以对引用类型设置为null。

假设上述的代码改为如下形式

static void Main(string[] args)

{

int k = 10;//k的生命周期开始了

for (int i = 0; i <= 10 - 1; i++)//i的生命周期开始了

{

int m = k + i;//m的生命周期开始了

k = null; //k的生命周期结束了???

for (int j = i; j <= 10 - 1; j++)//j的生命周期开始了

{

int n = j * i;//n的生命周期开始了

//n的生命周期结束了

}//j的生命周期结束了

//m的生命周期结束了

}//i的生命周期结束了

//k的生命周期结束了

}

你考虑下第七行代码

k = null; //k的生命周期结束了???

这时候栈应该怎么处理呢?想像下,堆栈图会怎么样呢?显然堆栈到了第三步就不知道怎么样才可以把变量k销毁了。

那为什么引用类型就可以设置为null呢?我们先看如下的代码

static void Main(string[] args)

{

System.Collections.ArrayList k = new System.Collections.ArrayList();//k的生命周期开始了

for (int i = 0; i <= 10 - 1; i++)//i的生命周期开始了

{

k.Add(i);

int m = k.Count;//m的生命周期开始了

for (int j = i; j <= 10 - 1; j++)//j的生命周期开始了

{

int n = j * i;//n的生命周期开始了

//n的生命周期结束了

}//j的生命周期结束了

//m的生命周期结束了

}//i的生命周期结束了

//k的生命周期结束了

}

对应的堆栈中的处理大致如图

我们可以看出变量k还是分配在堆栈中,但实际存放ArrayList实例的区域却是存储在堆中。对ArrayList的实例使用,是通过在堆栈中的变量k来间接的指向的。这样的好处是,将对象引用null和生命周期两个概念可以分离出来。

以下代码请仔细认知

我们可以很清晰的观察到,k的生命周期并没有发生变化,只是当k = null;后,变量k不再指向堆中的有效地址了。

现在我们明白了,因为值类型变量直接在Stack中保存了数据,因此在生命周期结束前数据不能被任何形式的销毁,而引用类型变量在Heap中保存数据,所以赋值null其实是将对应在Heap中的数据销毁而不是结束变量的生命周期。



本文转自shyleoking 51CTO博客,原文链接:http://blog.51cto.com/shyleoking/803155

相关文章
|
存储 C#
C# 值类型与引用类型 null与可空类型
本文目录 1. 值类型与引用类型 2. null的含义 3. 可空类型
161 0
|
Java
一起谈.NET技术,引用类型赋值为null与加速垃圾回收
  在标准的Dispose模式中,提到了需要及时释放资源,却并没有进一步细说让引用等于null是否有必要。   有一些人认为等于null可以帮助垃圾回收机制早点发现并标识对象是垃圾。其他人则认为这没有任何帮助。
655 0
|
Java
引用类型赋值“.NET技术”为null与加速垃圾回收
  在标准的Dispose模式中,提到了需要及时释放资源,却并没有进一步细说让引用等于null是否有必要。   有一些人认为等于null可以帮助垃圾回收机制早点发现并标识对象是垃圾。其他人则认为这没有任何帮助。
766 0
|
Java C#
改善C#程序的建议5:引用类型赋值为null与加速垃圾回收
原文:改善C#程序的建议5:引用类型赋值为null与加速垃圾回收 在标准的Dispose模式中(见前一篇博客“C#中标准Dispose模式的实现”),提到了需要及时释放资源,却并没有进一步细说让引用等于null是否有必要。
1050 0
|
19天前
|
机器学习/深度学习 SQL 关系型数据库
【MySQL进阶之路丨第十一篇】一文带你精通MySQL NULL值处理、正则表达式
【MySQL进阶之路丨第十一篇】一文带你精通MySQL NULL值处理、正则表达式
44 0
|
19天前
|
SQL 关系型数据库 MySQL
总结 vue3 的一些知识点:MySQL NULL 值处理
总结 vue3 的一些知识点:MySQL NULL 值处理
|
19天前
|
SQL 关系型数据库 MySQL
MySQL NULL 值处理
MySQL NULL 值处理
|
11天前
|
SQL 关系型数据库 MySQL
实时计算 Flink版产品使用合集之从MySQL同步数据到Doris时,历史数据时间字段显示为null,而增量数据部分的时间类型字段正常显示的原因是什么
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStreamAPI、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。