C# 数据类型、参数类型、可变字符串、方法重载、拆装箱

数据类型

数据类型主要分为值类型和引用类型,但这并不代表值类型就存储在栈中,引用类型就存储在堆中。一般的,变量在方法中声明,方法执行在栈中,执行完毕清除栈帧。所以在方法中声明的变量直接存储在栈中,那为什么还会有值类型和参数类型的区别呢?

值类型

值类型有int(4字节)、bool(1字节)、char(2字节)、float(8字节)等。

值类型直接存储数据,于声明处创建

这些类型所能存储的数据体积较小,根据上方所说,值类型便存储在栈中,它的数据也随之存储在栈中,待方法执行完成后清除。

引用类型

引用类型有string、Array、object(较特殊) 等等。

引用类型存储数据的引用(内存地址),引用指向所存储的数据,数据在另一处内存中存储

这些类型所能存储的数据体积较大或者未知(不固定),很难将其存储在空间本就不大的栈中,所以,这些类型的变量一般将数据存储在空间巨大的堆中,而将数据在堆中的地址存储在栈中。

在比较运算时,引用类型的变量比较的是变量存储的地址而非变量存储的数据。

 

字符串池

即在新建一个字符串,并想要为其赋值时,程序会先检索一遍堆中是否有相同的文本。若存在,则直接返回该对象的引用;否则,开辟空间,创建一个新的字符串数据,返回新文本的引用。

目的:提高内存利用率

如果想要强制创建新数据,new一个就好;

变量值变更

字符串具有不可变性

这些类型的数据在修改时,不能直接在数据自身(原本分配给自己的空间)上修改,毕竟谁知道下次要塞入一个什么庞然大物呢?修改后的数据比原本小还好说,产生空隙就行,然而一旦要修改的数据体积较原来大,那便会影响其他位置的存储。

所以这些引用类型的数据,若要修改,便在堆中另起炉灶,开辟一块新的空间用于修改后的数据存储,并将栈中的变量中存储的地址指向那片新的空间。

垃圾回收机制

垃圾回收机制(garbage collector)简称gc,用于清理堆中没有被引用(没有地址所指向)的数据,释放和回收这部分内存。

垃圾回收机制一般在系统内存快要告急的时候才进行,而这一gc机制必将消耗大量的性能,这就需要我们对gc进行的时间进行“建议”,以控制gc在对任务(用户)影响最小的情况下执行,例如游戏的暂停、动画播放等情况。

引用类型值修改!

上面已经提到引用变量的存储方式是分为两部分的,这也导致这种类型的数据在修改时会出现两种结果不同的操作方式!

修改中存储的引用

这种做法会将另一个堆中数据的地址赋值给变量,但是没有改变堆中原数据,其他引用原数据的变量不受影响。

int[] arr = new int[] { 1 } ;
int[] arr2 = arr ;

arr = new int[] {2} ;

Console.WriteLine(arr2[0])  ;

结果为  1

修改中存储的数据

这种做法会直接对堆中存储的数据进行修改,所有引用这个数据的变量均会发生改变。

int[] arr = new int[] { 1 } ;
int[] arr2 = arr ;

arr[0] = 2 ;
Console.WriteLine(arr2[0]) ;

结果为  2

也就是说,

如果等号左侧没有 [ ] ,那么就是修改栈中的引用 ;

如果等号左侧有 [ ],那么就是修改堆中存储的数据;

由于字符串的只读性,故字符串只能修改栈中的引用。

Object类型由于不能添加 [ ] ,故也只能创建新的数据并返回新的引用。


参数类型

与上方的值类型和引用类型对应,参数也有值参数和引用参数,此外,还附加了输出参数一类。

By the way,C#的方法中还有关键字 params (参数数组),用于不确定数量的参数接收,详细见我的             C#交错数组和参数数组http://t.csdn.cn/UHmf6  文章

值参数

  • 默认为值参数
  • 调用方法时复制实参变量所储存的内容
  • 作用:传递数据

引用参数

  • 使用 ref 关键字修饰
  • 调用方法时复制实参变量在栈中的应用
  • 作用:改变数据    方法内部修改引用参数,实质上就是在修改实参变量

ref 要求实参必须在传递前进赋值。

输出参数

  • 使用 out 关键字修饰。
  • 调用方法时复制实参变量在栈中的引用
  • 作用:返回结果    用于接收方法的结果,补充方法的输出数目,由于方法的返回值只能有一个,所以可以使用 out 来扩展

out 在使用前可以不赋值,但要求形参离开方法前必须赋值。


可变字符串

由于字符串的不可变性,就导致如果要对字符串进行修改,就必然要在内存中不断开辟新的空间、创建新的字符串,而这些字符串又是一次性的,这就导致连续的字符串修改会不断地产生内存中的“垃圾”,这就加大了机器的负担和消耗,降低性能。为此,有了可变字符串。

!!!!先加入using System.Text ;   !!!!!! 

StringBuilder 变量名 = new StringBuilder( 预设字符数 )

例如:

StringBuilder builder = new StringBuilder(10) ;
for (int i = 0; i < 10; i++)
{
    builder.Append(i) ;
}
Console.Write(builder) ;
结果 0123456789
  • 可变字符串可预先设置要开辟的空间大小,单位是字符(2字节)
  • 优点:可以在原有空间修改字符串,避免产生垃圾
  • 适用性:频繁对字符串操作(替换 增加 移除)

还有许多方法,例如:

builder.Replace()
builder.Remove()

方法重载

两个方法名称相同,但参数列表不相同,用于在不同条件下解决同一类型的问题,例如Console.WriteLine()。

需要注意的是:

  1. 所重载的方法需要在同一个类Class下
  2. 如果参数个数相同,则参数的类型不能相同
  3. 如果参数类型相同,则参数的个数不能相同
  4. 仅out与ref的区别不可以构成重载


拆装箱

装箱操作

“比较”消耗性能 (最)远大于拆箱性能消耗

值类型隐式转换为 object 类型或由此值类型实现的任何接口类型的过程。

int a = 1 ; 

object o = a ;

内部机制:

  1. 在堆中开辟内存空间
  2. 将值类型的数据复制到堆中
  3. 返回堆中新分配对象的地址

拆箱操作

“比较”消耗性能

从object类型或从接口类型到实现该接口的值类型的显式转换。

int b = (int) o ;

内部机制:

  1. 判断给定类型是否是装箱时的类型
  2. 返回已装箱实例中属于原值类型字段的地址

如何防止拆装箱

然而对于现在的计算机性能来说,拆装箱对于性能并不会产生什么明显的负担,但是面试可能会考?

什么会引发拆装箱?

方法的形参是object类型,而实参传递值类型,则会触发装箱

例如 “23”+33,实际上是使用了string.Concat()方法,相当于string.Concat(“23”,33),string.Concat()的形参为object类型。而这将会导致拆装箱动作,但23”+“33”不会,所以可以用 .ToString先将其转换为字符串再进行拼接。

如何避免

可以通过使用方法重载、泛化来避免参数中object类型的使用


结语

本文算是达内科技游戏制作网课的课后笔记吧,大量内容为老师所授,吹一波祁天暄老师嗷

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值