IL代码检测Main的代码引用的所有类型,分配一个内部结构来管理都引用类型的访问
jitcompiler:
1 在元数据中查找被调用的方法
2 从元数据中获取该方法的IL
3 分配内存块
4 将IL编译成本机cpu指令,存到3分配的地址
5在type表修改与方法对应的条目,使它指向步骤3的内存块
6 跳转到内存块中的本机代码
第二次调用的时候是不需再调用jitcompiler函数的
5.1 int类型不管是在64位还是32位机器, 对C#来说都是对应Int32.
5.1值类型:所有值类型都成为结构或者枚举
所以这个所谓的“提领”其实就是“获取指针地址或引用地址上的值”的意思,按照构词法可直译为“引用解析”
声明为值类型的条件:
1,类型具有基元类型的行为。
2,类型不需要继承自其它类型。
3,类型也不需要派生出其它类型。
还有满足一下之一:
1,类型的实例较小(16字节或者更小--很难吧??)
2,类型的实例较大,但不作为方法实参传递,也不从方法返回。--有感
区别:
1未装箱、已装箱 ;已
2,值类型兄ValueType派生
3,不能继承派生,struct的方法都隐式密封
4,初始值; null
5,逐字段复制;内存地址复制
6,自成一体;多个引用一个对象操作会互相影响
7,过了生命周期立即释放内存不等垃圾回收;等垃圾回收
值类型调用虚方法,要装箱
5.2 引用类型总是从托管堆里分配:
-
分配引用类型对象
1.内存从托管堆分配
2.堆上分配的每个对象都有一些额外的成员(还需要是初始化了的)
3.对象中的其他字节设为零
4.托管堆分配对象可能会触发GC的条件(比如内存不够) -
所有的值类型都隐式继承了ValueType, 如果引用类型隐式继承了Object一样, 所以,不能要继承其他类了
扩展:值、引用类型并不能继承ValueType(即使他是abstract class) net做了特殊处理 -
内存分配情况:
hashCode的通用规定:
在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对同一个对象的多次调用,hashCode方法都必须始终返回同一个值。在一个应用程序与另一个应用程序的执行过程中,执行hashCode方法所返回的值可以不一致。
如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象中的hashCode方法都必须产生同样的整数结果
如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中的hashCode方法,则不一定要求hashCode方法必须产生不用的结果。但是程序员应该知道,给不相等的对象产生截然不同的整数结果,有可能提高散列表的性能。
由上面三条规定可知,如果重写了equals方法而没有重写hashCode方法的话,就违反了第二条规定。相等的对象必须拥有相等的hash code。
5.3不能用接口更改已装箱的值类型中的字段
Point p = new Point(1, 1);
Console.WriteLine(p);
p.Change(2, 2);
Console.WriteLine(p);
Object o = p;
Console.WriteLine(o);
((Point)o).Change(3, 3);
//输出 2,2 --不是预期的样子,所以不能用接口更改已装箱的值类型中的字段 !!!
Console.WriteLine("-3-" + o);
5.5 dynamic基元类型
如果字段、方法参数、方法返回值是dynamic,编译器会转换其为object(如果是值类型,就会装箱)。
编译时可隐性转换,且不会编译错误,但是如果类型不可转换时将会在运行时报错。
dynamic有额外消耗慎用