您的位置:首页 > 其它

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

2017-10-28 09:51 381 查看
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.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派生。



注意:上图不是按结构枚举进行划分的,只是一个示例图

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




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.


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息