浅谈C#中的值类型和引用类型
在C#中,值类型和引用类型是相当重要的两个概念,必须在设计类型的时候就决定类型实例的行为。如果在编写代码时不能理解引用类型和值类型的区别,那么将会给代码带来不必要的异常。很多人就是因为没有弄清楚这两个概念从而在编程过程中遇到了很多问题,在这里博主浅谈对值类型和引用类型的认识。
首先从概念上看,值类型直接存储其值,而引用类型存储对其值的引用。从而这两种类型存储在内存的不同地方。
其次从内存空间上看,值类型是在栈中操作,而引用类型则在堆中分配存储单元。
栈在编译的时候就分配好内存空间,在代码中有栈的明确定义,而堆是程序运行中动态分配的内存空间,可以根据程序的运行情况动态地分配内存的大小。因此,值类型总是在内存中占用一个预定义的字节数。而引用类型的变量则在栈中分配一个内存空间,这个内存空间包含的是对另一个内存位置的引用,这个位置是托管堆中的一个地址,即存放此变量实际值的地方。
也就是说值类型相当于现金,要用就直接用,而引类型相当于存折,要用得先去银行取。
但值类型在栈上分配内存,而引用类型在托管堆上分配内存,只是一种笼统的说法。下面对其进行详细描述。
(1)对于值类型的实例,如果作为方法中的局部变量,则被创建在线程栈上;如果该实例作为类型的成员,则作为类型成员的一部分,连同其他类型字段存放在托管堆上。
每种值类型均有一个隐式的默认构造函数来初始化该类型的默认值。例如:
int i = new int();
等价于:
Int32 i = new Int32();
等价于:
int i = ;
等价于:
Int32 i = ;
使用new运算符时,将调用特定类型的默认构造函数并对变量赋以默认值。在上例中,默认构造函数将值0赋给了i。
说明:C#的所有值类型均隐式派生自System.ValueType,而System.ValueType直接派生于System.Object。即System.ValueType本身是一个类类型,而不是值类型。其关键在于ValueType重写了Equals方法,从而对值类型按照实例的值来比较,而不是引用地址来比较。
(2)引用类型的实例创建在托管堆上。
下面以一段代码来详细讲解一下值类型与引用类型的区别
namespace Test
{
class Program
{
static void Main(string[] args)
{
//调用ReferenceAndValue类中的Demonstration方法
ReferenceAndValue.Demonstration();
Console.ReadLine();
}
}
public class stamp //定义一个类
{
public string Name { get; set; } //定义引用类型
public int Age { get; set; } //定义值类型
}
public static class ReferenceAndValue //定义一个静态类
{
public static void Demonstration() //定义一个静态方法
{
stamp Stamp_1 = new stamp { Name = "Premiere", Age = }; //实例化
stamp Stamp_2 = new stamp { Name = "Again", Age = }; //实例化
int age = Stamp_1.Age; //获取值类型Age的值
Stamp_1.Age = ; //修改值类型的值
stamp guru = Stamp_2; //获取Stamp_2中的值
Stamp_2.Name = "Again Amend"; //修改引用的Name值
Console.WriteLine("Stamp_1's age:{0}", Stamp_1.Age); //显示Stamp_1中的Age值
Console.WriteLine("age's value:{0}", age); //显示age值
Console.WriteLine("Stamp_2's name:{0}", Stamp_2.Name); //显示Stamp_2中的Name值
Console.WriteLine("guru's name:{0}", guru.Name); //显示guru中的Name值
}
}
}
通过运行上面一段程序之后我们可以看出,当改变了Stamp_1.Age的值时,age并没有跟着变,但在改变了anders.Name的值后,guru.Name却跟着变了,这就是值类型和引用类型的区别。在声明age值类型变量时,将 Stamp_1.Age的值赋给它,这时,编译器在栈上分配了一块空间,然后把Stamp_1.Age的值填进去,二者没有任何关联,就像在计算机中复制文件一样,只是把Stamp_1.Age的值拷贝给age了。而引用类型则不同,在声明guru时把Stamp_2赋给它,前面说过,引用类型包含的只是堆上数据区域地址的引用,其实就是把Stamp_2的引用也赋给guru,因此它们指向了同一块内存区域。既然是指向同一块区域,不管修改谁,另一个的值都会跟着改变,就像信用卡跟亲情卡一样,用亲情卡取了钱,与之关联的信用卡账上也会跟着发生变化。
作者:耑新新,发布于 博客园
转载请注明出处,欢迎邮件交流:zhuanxinxin@aliyun.com
浅谈C#中的值类型和引用类型的更多相关文章
- 【.Net】浅谈C#中的值类型和引用类型
在C#中,值类型和引用类型是相当重要的两个概念,必须在设计类型的时候就决定类型实例的行为.如果在编写代码时不能理解引用类型和值类型的区别,那么将会给代码带来不必要的异常.很多人就是因为没有弄清楚这两个 ...
- C# 中的值类型和引用类型
原文 C# 中的值类型和引用类型 值类型(value type):int,long,float,double,decimal,char,bool 和 struct 统称为值类型.值类型变量声明后,不管 ...
- C++ : 从栈和堆来理解C#中的值类型和引用类型
C++中并没有值类型和引用类型之说,标准变量或者自定义对象的存取默认是没有区别的.但如果深入地来看,就要了解C++中,管理数据的两大内存区域:栈和堆. 栈(stack)是类似于一个先进后出的抽屉.它的 ...
- C#中的值类型和引用类型,深拷贝,浅拷贝
from https://www.jianshu.com/p/2d27b06e253f 一.C#中的值类型和引用类型 概念 值类型直接存储其值. 引用类型存储对值的引用. 说起来有些拗口,其本质是Va ...
- .NET中的值类型与引用类型
.NET中的值类型与引用类型 这是一个常见面试题,值类型(Value Type)和引用类型(Reference Type)有什么区别?他们性能方面有什么区别? TL;DR(先看结论) 值类型 引用类型 ...
- Windows Phone 开发起步之旅之二 C#中的值类型和引用类型
今天和大家分享下本人也说不清楚的一个C#基础知识,我说不清楚,所以我才想把它总结一下,以帮助我自己理解这个知识上的盲点,顺便也和同我一样不是很清楚的人一起学习下. 一说起来C#中的数据类型有哪些,大 ...
- C#中对值类型和引用类型的一点认识
区别值类型和引用类型的重要一点就是值类型赋值的时候是给出一块内存空间,空间里放下要赋给值类型的值.而引用类型是开辟一块内存空间,空间里放下的是要赋给引用类型值的指向地址. 就像一个是复制了银行卡里的现 ...
- js中的值类型和引用类型的区别
1.JavaScript中的变量类型有哪些? (1)值类型(基本类型):字符串(String).数值(Number).布尔值(Boolean).Undefined.Null (这5种基本数据类型是按 ...
- C#中的值类型、引用类型,代码告诉你他是什么类型。
C#代码告诉你这是什么类型. using System; using System.Collections.Generic; using System.Linq; using System.Text; ...
随机推荐
- Html和websocket初识
一.web框架 众所周知,对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. import socket def handle_request(c ...
- scrum敏捷开发重点介绍
参考: http://www.scrumcn.com/agile/scrum-knowledge-library/scrum.html https://www.zhihu.com/question/3 ...
- classpath 及读取 properties 文件
java代码中获取项目的静态文件,如获取 properties 文件内容是必不可少的. Spring 下只需要通过 @Value 获取配置文件值 <!-- 资源文件--> <util ...
- [HNOI 2013]切糕
COGS 2398. [HNOI 2013]切糕 http://www.cogs.pro/cogs/problem/problem.php?pid=2398 ★★★☆ 输入文件:nutcake.i ...
- Java使用UDP发送数据到InfluxDB
最近在做压测引擎相关的开发,需要将聚合数据发送到InfluxDB保存以便实时分析和控制QPS. 下面介绍对InfluxDB的使用. 什么是InfluxDB InfluxDB是一款用Go语言编写的开源分 ...
- Java8 新特性 Streams map() 示例
在Java 8中stream().map(),您可以将对象转换为其他对象.查看以下示例: 1.大写字符串列表 1.1简单的Java示例将Strings列表转换为大写. TestJava8.java p ...
- H.265 Video Encoder IP Core
复制: 开源H.265硬件视频编码器H.265 Video Encoder IP Core是开源的H.265硬件视频编码器,实现了H.265(或叫HEVC)的大部分功能. 它由复旦大学专用集成电路与系 ...
- 【leetcode 简单】 第九十一题 找不同
给定两个字符串 s 和 t,它们只包含小写字母. 字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母. 请找出在 t 中被添加的字母. 示例: 输入: s = "abcd&quo ...
- HDU 3065 病毒侵袭持续中 (AC自动机)
题目链接 Problem Description 小t非常感谢大家帮忙解决了他的上一个问题.然而病毒侵袭持续中.在小t的不懈努力下,他发现了网路中的"万恶之源".这是一个庞大的病毒 ...
- sqlalchemy操作数据库(二)
sqlalchemy的基本操作 表结构如下: from sqlalchemy import create_enginefrom sqlalchemy.ext.declarative importdec ...