值类型与引用类型及在内存中的存储
来源:互联网 发布:怎样成为淘宝会员 编辑:程序博客网 时间:2024/05/22 15:27
如果数据类型在它自己分配的内存中存的是具体数据,则该数据类型就是“值类型”;如果存储的是指向一个地址的指针,那么该数据类型是“引用类型”。
值类型
值类型包括:
所有数字数据类型
Boolean、Char 和 Date
所有结构,即使其成员是引用类型
枚举,因为其基础类型总是 SByte、Short、Integer、Long、Byte、UShort、UInteger 或 ULong
引用类型
引用类型包括:
String
所有数组,即使其元素是值类型
类类型,如 Form
委托
public string get() { mypost op = new mypost(); mypost opp = op; op.subject = "I am right!"; string s = "Iamright_str"; set(op,ref s); return op.subject + "" + s + "" + opp.subject; } public void set(mypost op ,ref string str) { mypost o = op; op.subject = "I am wrong!"; str = "Iamwrong_str!"; }
调用GET() 输出:I am wrong!Iamwrong_str!I am wrong!
因为OP,OPP都是引用类型,所以当类的实例OP作为参数传递给SET时,传递的是一个地址,如果实际储存的值(实例)改变,他会跟着改变。OPP存储的地址与OP一致。如图:
但是注意这里,string参数需要加上ref才是传递地址,否则会像值类型一样不改变内容。
这是因为string是特殊的引用类型(编译器对其做了特殊处理),不然MSDN也不会把它单独作为一类。
string最为显著的一个特点就是它具有恒定不变性:我们一旦创建了一个string,在managed heap 上为他分配了一块连续的内存空间,我们将不能以任何方式对这个string进行修改使之变长、变短、改变格式。所有对这个string进行各项操作(比如调用ToUpper获得大写格式的string)而返回的string,实际上另一个重新创建的string,其本身并不会产生任何变化。
string 对象称为不可变的(只读),因为一旦创建了该对象,就不能修改该对象的值。有的时候看来似乎修改了,实际是string经过了特殊处理,每次改变值时都会建立一个新的string对象,变量会指向这个新的对象,而原来的还是指向原来的对象,所以不会改变。这也是string效率低下的原因。
值类型和引用类型在内存中的存储
在我们使用类型时,代码里面必然少不了变量的声明,我们先看一下方法内的局部变量的声明,请看如下代码:
private static void Main(){ int i; MyClass mc; i = 5; mc = new MyClass();}
当一个局部变量声明之后,就会在栈的内存中分配一块内存给这个变量,至于这块内存多大,里面存放什么东西,就要看这个变量是值类型还是引用类型了。
l 值类型
如果是值类型,为变量分配这块内存的大小就是值类型定义的大小,存放值类型自身的值(内容)。比如,对于上面的整型变量i,这块内存的大小就是4个字节(一个int型定义的大小),如果执行i = 5;这行代码,则这块内存的内容就是5(如图-1)。
对于任何值类型,无论是读取还是写入操作,可以一步到位,因为值类型变量本身所占的内存就存放着值。
l 引用类型
如果是引用类型,为变量分配的这块内存的大小,就是一个内存指针(实例引用、对象引用)的大小(在32位系统上为4字节,在64位系统上为8字节)。因为所有引用类型的实例(对象、值)都是创建在堆上的,而这个为变量分配的内存就存放变量对应在堆上的实例(对象、值)的内存首地址(内存指针),也叫实例(对象)的引用。以图形化的方式展现仿佛是变量有一条线指向着它在堆中的实例(有如图-2),而如果变量的类型还没有被实例化,则为零地址(null、空引用)。
以下为执行mc = new MyClass();代码后,内存中的示例:
由图-2可知,变量mc中存放的是MyClass实例(对象)的对象引用,如果需要访问mc实例,系统需要首先从mc变量中得到实例的引用(在堆中的地址),然后用这个引用(地址)找到堆中的实例,再进行访问。需要至少2步操作才可以完成实例访问。
l 嵌套类型
“值类型存放在栈上,引用类型存放在堆上” 这个说法并不严谨,因为当类型嵌套时...且看下面的类型定义代码:
public struct MyStruct{ /* 注意:作为结构,内部字段是不能象下面所写那样,在声明时直接初始化的。 * 但这里为了节省篇幅,从表达语义的角度,直接在声明时初始化了 * 此结构的代码无法通过编译的 */ public int i = 5; //值类型 public System.Exception ex = new Exception(); //引用类型}
在MyStruct结构中,有2个字段,一个是值类型的i变量,一个是引用类型的ex变量。这种情况下,内存中应该是一个什么模样呢?
首先,变量i和ex作为MyStruct的成员,必然存放在MyStruct实例的内部,而变量i作为值类型,其值就存放在自身;ex作为引用类型,变量内只存放实例(对象)的引用,而实例(对象)则在堆上创建,因此就有如图-5所示:
这样,值类型MyStruct的引用类型成员在内存上的地址是在Heap上的。同理,引用类型中的值类型其存储地址仍然是Heap而不是Stack。因此更严谨的说法应该是:
值类型变量的值存放在变量内部:若是局部变量,在Stack上;若是引用类型的成员,则在Heap上
引用类型变量的内容存放在堆上(always),变量本身在栈上存放一个指向堆中的引用
- 值类型与引用类型及在内存中的存储
- 基本类型数据在内存中的存储
- float 类型在内存中的存储方式
- int类型在内存中的存储方式
- float类型在内存中的存储
- float类型在内存中的存储方式
- float类型数据在内存中的存储
- int类型在内存中的存储方式
- float类型在内存中的存储方式
- 值类型和引用类型在内存上存储的不同
- C#引用类型和值类型的区别——值类型和引用类型在内存中的部署
- byte类型数据的取值范围及溢出后的强制转换及在内存中的存储结果
- 数据在内存中的存储之字符类型
- 程序在内存中的分布及变量类型
- Java中String类型笔试题目,对象声明与创建及在内存中的存贮
- Sql server 的表值函数是返回一个Table类型,table类型相当与一张存储在内存中的一张虚拟表。
- 基本类型和引用类型的变量在内存存放的内容及对象
- 负数在内存中的表示,int类型取值范围
- 十个著名悖论的最终解答 (转载)
- C++命名规范
- python 获取当前时间
- Arduino 摇杆控制 舵机
- 【Cocos2d-x游戏引擎开发笔记(3)】在屏幕上渲染菜单并添加消息响应
- 值类型与引用类型及在内存中的存储
- 最新在线客服漂浮代码下载
- 一个ant的build脚本。
- oracle简单存储过程(带参数)
- 对表进行dml操作时影响产生日志量的几个因素
- detours学习
- sql语句 update from
- c# 控件RadioButton
- visualvm远程监控(jstatd和jvm)