C# 入门一一值类型和引用类型

一、值类型和引用类型的区别

上表区别中,关于值的存储方式:通常被分配在线程的堆栈上,表明还有个例:

(1). 在引用类型中嵌套值类型

(2). 值类型装箱

这两种情况下,值类型的实例会被分配到托管堆中。

1. 引用类型中嵌套定义值类型

      如果类的字段类型是值类型,它将作为引用类型实例的一部分,被分配到托管堆中。但那些作为局部变量(例如下列代码中的c变量)的值类型,则仍会被分配到线程堆栈中。

public class NestedValueTypeInRef
{
	//valuetype作为引用类型的一部分被分配到托管堆上
	private int valuetype = 3;

	public void method( )
	{
		// c被分配到线程堆栈上
		char c = 'c';
	}
}

class Program
{
	static void Main( string[ ] args )
	{
		NestedValueTypeInRef reftype = new NestedValueTypeInRef( );
	}
}

2. 值类型嵌套定义引用类型

值类型嵌套定义引用类型时,堆栈上将保存该引用类型的引用,而实际的数据则依然保存在托管堆中。

public class TestClass
{
	public int x;
	public int y;
}

public class NestedRefTypeInValue
{
	//结构体字段,注意,结构体中字段不能被初始化
	private TestClass classinValuetype;

	public NestedRefTypeInValue(TestClass t)
	{
		classinValuetype.x = 3;
		classinValuetype.y = 5;
		classinValuetype = t;
	}
}

class Program
{
	static void Main( string[ ] args )
	{
		NestedRefTypeInValue reftype = new NestedRefTypeInValue( new TestClass());
	}
}

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

二、装箱与拆箱

装箱:将值类型转换为引用类型的过程

拆箱:将引用类型转换为值类型的过程

三、参数传递问题剖析

1. 值类型参数的按值传递

       值类型的按值传递,传递的只是该值类型的一个副本,被调用方法操作的是实参的一个副本而已,方法对参数的改变不会影响到实参的值。

private static void Add( int add_num )
{
	add_num += 1;
	Console.WriteLine( "方法中的add_num值:" + add_num );
}

static void Main( string[ ] args )
{
	Console.WriteLine( "值类型按值传递的情况" );
	int addNum = 1;
	Add( addNum );
	Console.WriteLine( "调用方法后,实参addNum值:" + addNum );
	Console.Read( );
}

运行结果:

2. 引用类型参数的按值传递

      当传递的参数是引用类型时,传递和操作的目标是指向对象的地址,而传递的实际内容是对地址的复制。由于地址指向的是实参的值,当方法对地址进行操作时,实际上操作了地址所指向的值。调用方法后原来实参的值就会被修改。

public class RefClass
{
	public int addNum;
}

class Program
{
	//引用类型按值传递的情况,addnumRef为形参
	private static void AddRef( RefClass addnumRef )
	{
		addnumRef.addNum += 1;
		Console.WriteLine( "方法中的addNum的值:" + addnumRef.addNum );
	}

	static void Main( string[ ] args )
	{
		Console.WriteLine( "引用类型按值传递的情况" );
		RefClass refClass = new RefClass( );
		refClass.addNum = 1;
		//refClass是实参,此时参数是引用类型
		AddRef( refClass );
		Console.WriteLine( "调用方法后,实参addNum值:" + refClass.addNum );
		Console.Read( );
	}
}

运行结果:

3. string引用类型参数按值传递的特殊情况

由于string具有不变性,一旦一个string类型被赋值,则它就是不可改变的,即不能通过代码去修改它的值。

public class RefClass
{
	public int addNum;
}

class Program
{
	//string引用类型按值传递的特殊情况
	private static void ChangeStr( string oldStr )
	{
		oldStr = "New string";
		Console.WriteLine( "方法中的oldStr的值:" + oldStr );
	}

	static void Main( string[ ] args )
	{
		Console.WriteLine( "string引用类型按值传递的特殊情况" );
		string str = "old string";
		ChangeStr( str );
		Console.WriteLine( "调用方法后,实参str值:" + str );
		Console.Read( );
	}
}

运行结果:

4. 值类型和引用类型参数按引用传递

       不管是值类型还是引用类型,都可以使用ref或out关键字来实现参数的按引用传递。并且在按引用传递时,方法的定义和调用都必须显示地使用ref或out关键字。

//值类型参数按引用传递的情况
private static void ChangeByValue( ref int numValue )
{
	numValue = 10;
	Console.WriteLine( numValue );
}

//引用类型参数按引用传递的情况
private static void ChangeByRef( ref string numRef )
{
	numRef = "new string";
	Console.WriteLine( numRef );
}

static void Main( string[ ] args )
{
	Console.WriteLine( "值类型和引用类型参数按引用传递的情况" );
	//num是值类型实参
	int num = 1;
	//refStr是引用类型实参
	string refStr = "old string";

	//值类型参数按引用传递
	ChangeByValue( ref num );
	Console.WriteLine( num );

	//引用类型参数按引用传递
	ChangeByRef( ref refStr );
	Console.WriteLine( refStr );

	Console.Read( );
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值