C# 值类型和引用类型

参考: 李志. Learning hard C#学习笔记 (图灵原创) (p. 86). 人民邮电出版社. Kindle 版本.

 

值 类型 通常 被 分配 到 线程 的 堆栈 上, 而 引用 类型 则 被 分配 到 托管 堆 上。

不同 的 分配 位置 导致 了 不同的 管理 机制, 值 类型 的 管理 由 操作系统 负责, 而 引用 类型 的 管理 则由 垃圾 回收 器( 又称 为 Garbage Collection, GC) 负责。

管理 主要 指 对内 存 空间 进行 分配 和 释放。

值 类型 实例 不一定 总会 被 分配 到 线程 栈 上。 在 引用 类型 中 嵌套 值 类型 时, 或者 在 值 类型 装箱 的 情况下, 值 类型 的 实例 就会 被 分配 到 托管 堆 中。

 

值 类型 实例 总会 被 分配 到 它 声明 的 地方, 声明 的 是 局部 变量 时, 将被 分配 到 栈 上, 而 声明 为 引用 类型 成员 时, 则 被 分配 到 托管 堆 上; 而 引用 类型 实例 总是 分配 到 托管 堆 上。

值 类型 继承 自 ValueType, ValueType 又 继承 自 System. Object; 而 引用 类型 则 直接 继承 于 System. Object。

值 类型 的 内存 不受 GC( 垃圾 回收 器) 控制, 作用域 结束 时, 值 类型 会被 操作系统 自行 释放, 从而 减少 了 托管 堆 的 压力; 而 引用 类型 的 内存 管理 则由 GC 来 完成。 所以 与 引用 类型 相比, 值 类型 在 性能 方面 更具 优势。

若 值 类型 是 密封 的( sealed), 你将 不 能把 值 类型 作为 其他 任何 类型 的 基 类; 而 引用 类型 则 一般 具有 继承性, 这里 指的 是 类 和 接口。

值 类型 不 能为 null 值, 它 会被 默认 初始 化为 数值 0; 而 引用 类型 在 默认 情况下 会 初始 化为 null 值, 表示 不 指向 托管 堆 中的 任何 地址。

对 值 为 null 的 引用 类型 的 任何 操作, 都会 引发 NullReferenceExcption 异常。 由于 值 类型 变量 包含 其实 际 数据, 因此 在 默认 情况下, 值 类型 之间 的 参数 传递 不会 影响 变量 本身;

而 引用 类型 变量 保存 的 是 数据 的 引用 地址, 它们 作为 参数 被 传递 时, 参数 会 发生 改变, 从而 影响 引用 类型 变量 的 值。

 

隐式 类型 转换。 由 低级 别 类型 向 高级 类型 的 转换 过程。 例如, 派生 类 可以 隐式 地 转换 为 它的 父 类, 装箱 过程 就 属于 这种 隐式 类型 转换。

装箱 指的 是将 值 类型 转换 为 引用 类型 的 过程, 而 拆 箱 指的 是将 引用 类型 转换 为 值 类型。 装箱 过程中, 系统 会在 托管 堆 中 生成 一份 堆栈 中 值 类型 对象 的 副本;

而 拆 箱 则是 从 托管 堆 中将 引用 类型 所 指向 的 已 装箱 数据 复制 回 值 类型 对象 的 过程。

 

 

 

 

 

实际上 参数 传递 的 方式 共有 4 种 不同 的 情况:

值 类型 参数 的 按 值 传递

引用 类型 参数 的 按 值 传递

值 类型 参数 的 按 引用 传递

引用 类型 参数 的 按 引用 传递

 

posted @ 2021-08-27 11:22  小小林林  阅读(50)  评论(0编辑  收藏  举报