C#编程语言(七):值类型与引用类型
值类型与引用类型
值类型:派生自System.ValueType类的类型是值类型,派生自ValueType的类型都会自动在栈(stack)上进行分配,因此有一个可预测的生命周期,而且非常高效。
引用类型:在继承链上没有System.ValueType的类型(如System.Type、System.String、System.Array、System.Exception以及System.Delegate)不会在栈上分配,而是在垃圾回收堆(heap)上进行分配。
另:C#中的所有基类型都是结构类型(例如:int对应System.Int32结构),结构类型是值类型;类类型是引用类型;栈的执行效率要比堆的执行效率高,可是栈的资源有限,不适合处理大的逻辑复杂的对象。所以结构处理作为基类型对待的小对象,而类处理某个商业逻辑;因为结构是值类型所以结构之间的赋值可以创建新的结构,而类是引用类型,类之间的赋值只是复制引用;(所以在以结构为参数传递时,最好使用ref,这样只传递地址引用,能够提高效率,同时也应注意这样结构的值也会随着方法调用而改变)
从功能上说,ValueType的唯一目的是"重写"由Object定义的虚方法来使用基于值而不是基于引用的语法:
{
protected ValueType();
public override bool Equals(object obj);
public override int GetHashCode();
public override string ToString();
}
由于值类型是基于值语法的,结构(包括所有数值数据类型如Int32等、自定义结构、枚举)的生命周期都是可预测的。但结构离开定义的作用域时,就会立即从内存中清除。
{
int i=0;//int是System.Int32结构
Point p=new Point();//Point是自定义结构
}
值类型与类类型的赋值
当把值类型赋值给另外一个时,是对字段成员逐一进行复制。对于System.Int32这样简单的数据类型,唯一需要复制的成员就是数值。而对像Point复杂点的自定义结构,就需要把Point所有的字段复制到新的结构变量中。改变新的结构变量的字段的值不会影响原结构变量的字段值。
当对引用类型进行复制时,是把原引用变量的地址指向赋给新的引用变量,两个引用变量指向同一个对象。
struct Point
{
public int X;
public int Y;
public Point(int XPos, int YPos)
{
X = XPos;
Y = YPos;
}
public void Increment()
{
X++; Y++;
}
public void Decrement()
{
X--; Y--;
}
public void Display()
{
Console.WriteLine("X = {0}, Y = {1}", X, Y);
}
}
//PointRef类型的定义
class PointRef
{
public int X;
public int Y;
public PointRef(int XPos, int YPos)
{
X = XPos;
Y = YPos;
}
public void Increment()
{
X++; Y++;
}
public void Decrement()
{
X--; Y--;
}
public void Display()
{
Console.WriteLine("X = {0}, Y = {1}", X, Y);
}
}
static void Main(string[] args)
{
Console.WriteLine("***** 值类型 / 引用类型 *****\n");
ValueTypeAssignment();
ReferenceTypeAssignment();
Console.ReadLine();
}
static void ValueTypeAssignment()
{
Console.WriteLine("指定值类型\n");
Point p1 = new Point(10, 10);
Point p2 = p1;
p1.Display();
p2.Display();
p1.X = 100;
Console.WriteLine("\n=> 改变 p1.X\n");
p1.Display();
p2.Display();
}
static void ReferenceTypeAssignment()
{
Console.WriteLine("指定引用类型\n");
PointRef p1 = new PointRef(10, 10);
PointRef p2 = p1;
p1.Display();
p2.Display();
p1.X = 100;
Console.WriteLine("\n=> 改变 p1.X\n");
p1.Display();
p2.Display();
}
包含引用类型的值类型
默认情况下,但值类型包含其他引用类型时,赋值将产生一个引用副本。这样就有两个独立的结构,每个都包含指向内存中同一个对象的引用(也就是浅复制)。当先执行深度赋值(将引用的对象的状态完全复制到新的对象中)时,引用类型就需要实现ICloneable结构。
{
public string infoString;
public ShapeInfo(string info)
{ infoString = info; }
}
struct Rectangle
{
public ShapeInfo rectInfo;
public int rectTop, rectLeft, rectBottom, rectRight;
public Rectangle(string info, int top, int left, int bottom, int right)
{
rectInfo = new ShapeInfo(info);
rectTop = top; rectBottom = bottom;
rectLeft = left; rectRight = right;
}
public void Display()
{
Console.WriteLine("String = {0}, Top = {1}, Bottom = {2}, Left = {3}, Right = {4}",
rectInfo.infoString, rectTop, rectBottom, rectLeft, rectRight);
}
}
static void Main(string[] args)
{
Console.WriteLine("***** 值類型 / 引用類型 *****\n");
ValueTypeContainingRefType();
Console.ReadLine();
}
static void ValueTypeContainingRefType()
{
Console.WriteLine("-> 創建 r1");
Rectangle r1 = new Rectangle("初始的信息", 10, 10, 50, 50);
Console.WriteLine("-> 把r1賦給r2");
Rectangle r2 = r1;
Console.WriteLine("-> 改變r2的值");
r2.rectInfo.infoString = "新的字符信息!";
r2.rectBottom = 4444;
r1.Display();
r2.Display();
}
可以看出,当使用r2的引用改变信息字符串的值时,r1的引用显示了同样的值(r1的引用的值也改变了)。
按值转递引用类型与按引用转递引用类型
引用类型可以作为参数传递给类型成员。但是,按按值转递一个对象与按引用转递一个对象大有不同。
{
//按值傳遞
Console.WriteLine("*********按值傳遞引用類型對象*****");
Car c = new Car("寶馬", 100);
Console.WriteLine("按值傳遞前對象的狀態。");
c.Print();
SendACarByValue(c);
Console.WriteLine("按值傳遞後對象的狀態。");
c.Print();
Console.ReadLine();
//按引用傳遞
Console.WriteLine("*********按值傳遞引用類型對象*****");
Car bmw = new Car("寶馬", 100);
Console.WriteLine("按引用傳遞前對象的狀態。");
bmw.Print();
SendACarByReference(ref bmw);
Console.WriteLine("按引用傳遞後對象的狀態。");
bmw.Print();
Console.ReadLine();
}
static void SendACarByValue(Car c)
{
//改變c的Speed屬性的值
c.Speed = 150;
//給c重新賦值(賦予新的Car對象的指向)
c = new Car("保時捷", 250);
}
static void SendACarByReference(ref Car c)
{
//改變c的Speed屬性的值
c.Speed = 150;
//給c重新賦值(賦予新的Car對象的指向)
c = new Car("保時捷", 250);
}
class Car
{
public int Speed { get; set; }
public string Name { get; set; }
public Car(string n, int s)
{
this.Name = n;
this.Speed = s;
}
public Car() { }
public void Print()
{
Console.WriteLine("汽車{0}的速度是{1}", this.Name, this.Speed);
}
}
可以看出:
一、如果按值传递引用类型,被调用者可能改变对象的状态数据的值,但不能改变所引用的对象(不能指向另一个新的对象,即指向没有改变)。
二、如果按引用传递引用类型,被调用者可能改变对象的状态数据的值和所引用的对象(指向都改变了)。
小结
值类型与引用类型的比较:
问题 |
值类型 |
引用类型 |
这个类型分配在哪里? |
分配在栈(stack)上 |
分配在托管堆(heap)上 |
变量是怎么表示的? |
是副本 |
变量指向被分配的对象所占的内存 |
能否作为其他类型的基类? |
不能,是封闭(sealed)的 |
能,若没有声明是封闭时可以。 |
能为这个类型定义构造函数吗? |
能,但默认的构造函数被保留 (即自定义构造函数必须全部带有参数) |
能 |
这个类型的变量什么时候消亡? |
当超出定义它们的作用域时 |
当托管堆被垃圾回收器回收时 |
转载于:https://www.cnblogs.com/bruce-wong/archive/2011/03/01/1967107.html
C#编程语言(七):值类型与引用类型相关推荐
- [你必须知道的.NET]第九回:品味类型---值类型与引用类型(中)-规则无边
发布日期:2007.5.28 作者:Anytao ©2007 Anytao.com ,原创作品,转贴请注明作者和出处. 接上回[第八回:品味类型---值类型与引用类型(上)-内存有理]的探讨,继续我们 ...
- C#值类型与引用类型
C#值类型与引用类型 值类型 存储的是实际的数据值. C#的值类型,包括整数型.实数型.逻辑型.字符型.枚举.结构等. 引用类型 本身不存储数据值,存储对这些实际数据的引用,也就是地址. 区别 值类型 ...
- 第八回:品味类型---值类型与引用类型(上)-内存有理
第八回:品味类型---值类型与引用类型(上)-内存有理 http://www.cnblogs.com/anytao/archive/2007/05/23/must_net_08.html 发布日期:2 ...
- swift string转int_swift中结构体和类的区别(值类型和引用类型的区别)
在swift中结构体和类有着更多的相同之处,在一般的使用中能够做到互相替换.我们可以先看看官方文档的描述: Unlike other programming languages, Swift does ...
- [你必须知道的.NET]第十回:品味类型---值类型与引用类型(下)-应用征途
本文将介绍以下内容: 类型的基本概念 值类型深入 引用类型深入 值类型与引用类型的比较及应用 [下载]:[类型示例代码] 1. 引言 值类型与引用类型的话题经过了两个回合([第八回:品味类型---值类 ...
- [你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理
本文将介绍以下内容: 类型的基本概念 值类型深入 引用类型深入 值类型与引用类型的比较及应用 1. 引言 买了新本本,忙了好几天系统,终于开始了对值类型和引用类型做个全面的讲述了,本系列开篇之时就是因 ...
- C# 值类型与引用类型(1)
1. 主要内容 类型的基本概念 值类型深入 引用类型深入 值类型与引用类型的比较及应用 2. 基本概念 C#中,变量是值还是引用仅取决于其数据类型. C#的基本数据类型都以平台无关的方式来定义,C#的 ...
- 【转】[你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理...
引用自:http://www.cnblogs.com/anytao/category/155694.html 作者:Anytao 本文将介绍以下内容: 类型的基本概念 值类型深入 引用类型深入 值类型 ...
- LV2之-----js 值类型和引用类型(基石1)
一.学习目标 1.值类型和引用类型的基本概念 2.常见的值类型和引用类型都有哪些? 3.数据类型检测 4.值类型和引用类型在内存中的存储机制 5.创建对象的方式有哪些? 6.对象属性名的点表示法和方括 ...
最新文章
- 软件工程个人作业02
- esxi安装ghost win7_针对Win7远程桌面的攻击实践(完美)
- Interview:算法岗位面试—11.02早上上海某银行(上海分行,四大行之一)信息技术岗笔试记录
- 移动端 Web 开发踩坑之旅
- 文献记录(part78)--Structure-Constrained Low-Rank Representation
- Java状态和策略设计模式之间的差异
- Apache实验-目录别名
- 数据结构思维 第十七章 排序
- flask-bootstrap插件
- 多个 vCenter Server 实例部署的升级或迁移顺序以及混合版本转换行为
- 针对xml文件做提取与写入的操作
- 【RLchina第二讲】 Foundations of Reinforcement Learning
- nodejs 做后台的一个完整业务整理
- 如何监控防火墙后的流量?
- linux文本编辑器
- SLF4J user manual
- iOS 支付宝手机网站支付
- 刷百度权重那些不为人知的事情
- 【论】PISCES: A Programmable, Protocol-Independent Software Switch
- 【量化入门】通过几种常见的量化策略框架,学习量化炒股
热门文章
- python实训内容_Python实验课:Python元组数据及其运算
- Java笔记-AnnotationConfigApplicationContext在Spring中的例子
- 计算机图形学Web前端笔记-浏览器中心点转场景坐标理论及实现(two.js)
- canvas笔记-closePath函数的使用(含例子)
- java 8 java demo_Java 8 中的 Streams API Demo
- mac nginx php7 配置,mac os下配置nginx+php7.1+fastcgi
- java项目启动后运行方法_spring boot在启动项目之后执行的实现方法
- python数字排列组合去重_排列组合-生成集合的所有子集
- (王道408考研操作系统)第二章进程管理-第一节2:进程状态及其切换
- 用户模式下的线程同步