第5章:基元类型、引用类型和值类型(一)

5.1编程语言的基元类型
需要掌握:

1.什么是基元类型
2.它的特性
3.作者认为编程时使用FCL类型名称的理由
4.隐式转换和显示转换
5.字面值是什么
6.check和uncheck的基元类型操作:检查运算的上溢/下溢
7.了解运算上溢/下溢的相关知识
术语:
primitive type 基元类型
FCL(Framwork Class Library) Framwork类库
Overflow 上溢
Underflow 下溢
literal 直接量或文字常量或字面值
…………………………………………………………………………………….
……………………………………………………………………………………..
……………………………………………………………………………………..
…………………………………………………………………………………….
……………………………………………………………………………………..
1.什么是基元类型:编程语言直接支持的数据类型
2.它的特性:IL,相当于引用基元类型=对应的FCL类型名称的命名空间
3.作者认为编程时使用FCL类型名称的理由:
3.1本来一样的意思,被有些人误认为不一样
3.2本来不一样的意思,被有些人误认为一样
3.3用基元类型调用转换方法的时候,有些语句写的很别扭
3.4用惯了C#的人员会忘了C#中有些基元类型的意思在别的语言中没有这个意思
4.隐式转换和显示转换
4.1不损失数量级和精确度的情况下才能隐式转换,所以有这种说法,隐式转换总是从精度低的类型转成精度高的类型
4.2损失数量级或精确度的转换,必须进行显示转换,所以有这种说法,显示转换总是从精度高的类型转成精度低的类型
5.字面值:可看成是所属类型的实例,基元类型都可以写成字面值
6.check和uncheck的基元类型操作:检查运算的上溢/下溢
6.1C#允许程序员自己决定如何处理溢出,溢出检查默认关闭
6.2用/checked+编译器开关,指示在编译器生成代码时,使用加、减、乘、除和转换指令的溢出检查版本,这是全局的关闭或打开溢出检查开关。
6.3还可以在代码中对某一句,或某一段代码,执行打开/关闭溢出检查的开关
7.了解运算上溢/下溢的相关知识
7.1上溢:值超过了该类型所能表示的最大值
下溢:值低于该类型所能表示的最小值
7.2要分别考虑整数、浮点数、数组
对整数,溢出指代数值:小于最小值为下溢,大于最大值为上溢
对浮点数,溢出指绝对值:绝对值小于浮点数所能表示的最小值,为下溢,当作 0;绝对值大于浮点数所能表示的最大范围,为上溢,当作 INF。
根据具体符号的不同,又分为:正上溢、正下溢、负上溢、负下溢
还有就是在数组操作中,超出了数组的上界,就教作上溢,超出数组的下界,就是下溢

第5章:基元类型、引用类型和值类型(一)_第1张图片

5.2 引用类型和值类型
1.引用类型的四个特性
2.值类型的优点
3.引用类型是什么,值类型是什么
4.能用代码举例说明,引用类型和值类型的具体区别
5.什么情况下,可以将类型声明为值类型
6.值类型和引用类型的区别
7.拆箱、装箱(初步了解)
8.CLR如何控制类型中的字段分布
术语:
nullability 可空
immutable 不可变
……………………………………………………………………………………..分割线……………………………………………………………………………..
……………………………………………………………………………………..分割线……………………………………………………………………………..
……………………………………………………………………………………..分割线……………………………………………………………………………..
……………………………………………………………………………………..分割线……………………………………………………………………………..
……………………………………………………………………………………..分割线……………………………………………………………………………..
1.引用类型的四个特性
1.1内存必须从托管堆上分配
1.2**堆上分配的每个对象都有一些额外的成员,这些成员必须被初始化**
1.3**对象中的其他字节(为字段而设),总是设置为0**
1.4从托管堆分配对象时,可能强制进行一次垃圾回收

2.值类型的优点
2.1值类型的使用缓解了托管堆的压力
原因:值类型的变量,不包含指向实例的指针变量中包含了实例本身的字段,所以操作实例的字段时不必提领指针
2.1**减少了应用程序生存周期内垃圾回收的次数**
原因:值类型的实例,不受垃圾回收器的控制。方法调用完之后,值类型占用的内存,自动被释放。
3.引用类型是什么,值类型是什么
3.1引用类型:数组,类,接口,委托以及内置引用类型object和string
C#有以下一些引用类型:
数组(派生于System.Array)
用户定义的以下类型:
类:class(派生于System.Object);
接口:interface(接口不是一个“东西”,所以不存在派生于何处的问题。Anders在《C# Programming Language》中说,接口只是表示一种约定[contract]);
委托:delegate(派生于System.Delegate);
内置引用类型object(System.Object的别名);
内置引用类型string(System.String的别名)
3.2值类型:结构(Struct)和枚举(Enum)
C#中的部分结构:
System.SByte, System.Byte
System.Int16,System.UInt16
System.Int32,System.UInt32
System.Int64,System.UInt64
System.Char,
System.Single, System.Double,
System.Doolean,
System.Decimal
System.TimeSpan
C#中的部分枚举:
System.DayOfWeek
System.IO.FileAttributes
System.Drawing.FontStyle

所有的结构都是System.ValueType抽象类的直接派生类,System.ValueType又直接从System.Object派生。
所有枚举都从System.Enum抽象类中派生,System.Enum又是从System.ValueType派生。
根据定义,所有值类型都必须从System.ValueType派生。
第5章:基元类型、引用类型和值类型(一)_第2张图片
注意:上图不是按结构枚举进行划分的,只是一个示例图

4.能用代码举例说明,引用类型和值类型的具体区别

//引用类型(因为是'class')
class SomeRef{
public Int32 x;
}
//值类型(因为是'struct')
struct SomeVal{
public Int32 x;
}

stativ void ValueTypeDemo(){
SomeRef r1=new SomeRef();//堆上分配
SomeVal v1=new SomeVal();//栈上分配
r1.x=5;//提领指针
v1.x=5;//在栈上操作值
Console.WriteLine(r1.x);//输出5
Console.WriteLine(v1.x);//输出5

SomeRef r2=r1;//
SomeVal v2=v1;
r2.x=8;
v2.x=9;
Console.WriteLine(r1.x);//输出8
Console.WriteLine(v1.x);//输出5
Console.WriteLine(r2.x);//输出8
Console.WriteLine(v2.x);//输出9

第5章:基元类型、引用类型和值类型(一)_第3张图片

SomeVal v=new SomeVal();
Int32 a=v.x;

SomeVal v1;
Int32 a=v.x;

上述第一段代码中的写法,使用new操作符,CLR会认为实例以初始化,不报错,a的值为0;第二段代码报错,使用了可能未赋值的字段x
5.什么情况下,可以将类型声明为值类型
必须满足以下全部条件:
5.1具有基元类型的行为:没有成员会修改类型的任何实例字段
5.2不从其他任何类型派生
5.3也不派生其他任何类型
还有满足以下任意条件
5.4类型的实例较小(16字节或更小)
5.5类型的实例较大(大于16字节),但不作为方法实参传递,也不从方法返回。
6.值类型和引用类型的区别
6.1值类型和引用类型的回收机制不同:未装箱的值类型不再堆上分配,一旦定义了该类型的一个实例方法不再活动,为它们分配的存储就会释放
6.2**值类型变量复制的时候是逐行逐字段复制;引用类型变量复制的时候只复制内存地址**
6.3基于上一条,两个或多个引用类型变量可以引用堆中通一对象,所以,一个变量执行的操作可能影响另一变量引用的对象;值类型不会
6.4引用类型的变量包含的堆中对象的内存地址,创建时默认初始值是null,表示不指向有效对象,试图使用null应用类型的变量,会报NullReferenceException;值类型不会报这种错误,因为值类型的变量总是包含其基础类型的一个值,值类型的所有成员都初始化为0,(CLR运行为值类型添加”可空“(nullability)标识)
6.5值类型中不应该有虚方法不能有抽象方法,其所有的方法都必须是隐式封闭的。因为不能将值类型作为基类来定义新的值类型或新的引用类型
6.6值类型都是从ValueType派生的,ValueTyp是从Object派生的,所以提供了与Object相同的方法,但是ValueType重写了EqualsGetHashCode方法。Equals方法:当两个对象的字段值完全匹配的时候返回true。
GetHashCode方法:这个方法中的算法,在生成哈希码时会考虑对象的实例字段的值
( 由于这个默认实现存在性能上的问题,所以定义自己的值类型的时候,要重写这两个方法,并提供他们的显示实现)
6.7值类型变量有两种表现形式:未装箱和已装箱。引用类型变量总是处于已装箱形式

7.拆箱、装箱
装箱:
(1)把值类型转换成引用类型(Object)的隐式转换
(2)把值类型转换成该值类型继承(也可以叫做实现)的任何接口类型的隐式转换
拆箱:
(1)把已装箱的引用类型(Object)转换为值类型的显示转换
(2)把任何接口类型(Object)转换为实现该接口的值类型的显示转换
举例:

struct A : ICloneable 
{ 
public Int32 x; 
public override String ToString() { 
return String.Format(”{0}”,x); 
} 
public object Clone() { 
return MemberwiseClone(); 
} 
} 
static void main() 
{ 
A a; 
a.x = 100; 
Console.WriteLine(a.ToString()); 
Console.WriteLine(a.GetType()); 
A a2 = (A)a.Clone(); 
ICloneable c = a2;//装箱:因为值类型a2隐式转换为A所实现的接口类型ICloneable
A a3=(A)c;//拆箱:因为接口类型c显示转换为实现ICloneable的值类型A
Ojbect o = c.Clone(); 
} 

8.第5章:基元类型、引用类型和值类型(一)_第4张图片
第5章:基元类型、引用类型和值类型(一)_第5张图片

你可能感兴趣的:(NET,CLR,via,C#,:学习笔记,引用类型,值类型,基元类型)