这两章全是理论性的东西,我觉得不必过于钻牛角尖。理论这东西,只有在长期的实践中去慢慢领悟才会深刻。下面我只写些我认为重要的关键知识。
(一)类型转换
知识点:向基类型的转换被认为是一种安全的隐式转换;向派生类型转换时,只能显示转换。
举例:
Object o = new Employee(); Employee e = (Employee)o;
重要认知:CLR的类型检查会遍历继承层次结构,用每个基类型去核对指定的类型。
常用代码:(见下方代码段。CLR会检查两次对象的类型):
if(o is Employee){ Employee e = (Employee)o; }
简化代码:(见下方代码段。CLR会检查一次对象的类型)
Employee e = o as Employee; if(e != null){ //... }
(二)值类型和引用类型
重要认知:1.栈中储存的是值类型、引用类型的指针(地址);堆中存储引用类型本身(不全是,见2)。
2.包含在引用类型内的值类型不会被存储在栈中,而是堆中(还是值类型,未被装箱),它被包含于引用类型对象中。
(三)重视装箱和拆箱对程序性能的影响
理解以下代码中的三次装箱:
public static void Main(){ Int32 v=5; Object o =v; v=123; Console.WriteLine(v + ", " + (Int32)o ); }
第一次装箱是将v转换成object对象;第二次和第三次是因为WriteLine()方法要获取一个String对象,这样v和被拆箱的o会被再次装箱。
“装箱”发生的事情:
1. 在托管堆中分配内存,包括值类型字段需要的内存量+类型对象指针的内存量+同步块索引需要的内存量。
2. 值类型的字段复制到新分配的堆内存。
3. 返回对象的地址。(地址是对对象的引用(指针),值类型变成引用类型)
概念应用:
重写类中的ToString()方法,可以避免使用ToString()方法时的装箱问题。
public class A { private int x; public override String ToString() { return string.formart("{0}",x); } }
注意重写的ToString()方法内部如果调用了base.ToString();外部调用此方法时,值类型依然会被装箱。