首页 > 其他 > 详细

构造器

时间:2014-03-22 10:24:35      阅读:478      评论:0      收藏:0      [点我收藏+]
        直奔主题。
        我们知道类中存在两种构造器,即类型构造器和实例构造器。

        实例对象需要初始化,就是我们常说的new以下,其实new做了很多事,比如计算对象需要占用的内存空间,分配内存,初始对象的值,有时还会导致GC清理内存的操作。用一句行业语就是实例构造函数就是来构造实例对象的构造函数。
        和实例化对象道理一样,类型对象也需要被构建, 类型构造器就是来初始化类型对象的构造函数。

       不过这二者有点小不同。

       类型构造器:
       首先自然是类型构造器那么就只能执行一次构建,并且构建它的对象应该限于任何对象的产生(这里说的是AppDomain中的对象),换句话说它就该被CLR来调用,为了避免程序员去调用类型构造函数,类型构造函数被限定为private,但是如果你自己去体验编码是一定会骂我说谎,说加了private后编译器提示说类型构造函数前不能添加任何的访问修饰符,其实是这样滴,这个关键字会被编译器在编译阶段添加,所以你懂得。
       其次,类型构造器必须是静态的,其实我貌似犯了个错误,这一点好像应该放在第一点来说,因为类型构造器和类型字段一样道理,因为他的加载顺序应该在只要调用了该对象的任何实例之前就加载(这个我们后面在说关于系统调用的事)。
       第三点,有我说第一点可以理解,一般情况下带参的构造函数如果需要由程序来调用至少不应该是private,到不说构造函数不能使private,如果你将一个函数设为了private至少需要在一个非private的构造函数来调用它,否则,嘿嘿,你的这种做法有“代码异味”, 因为你的那个private的构造器就是一段没用的垃圾。因为我们说了类型构造器是private的并有CLR来调用,那么你要是弄个带参的,CLR多半要疯了,他怎么知道该给你穿什么玩意啊。所以规定类型构造器必须是无参的

        实例构造器:
       实例构造器,这个就不想多说了,这个应该很熟悉,只要不加static随你怎么玩儿,出来private的构造器需要被其他构造函数调用外,你自己就看着办吧,只要是需要的你就可以玩儿。

       还是来看看IDasm给我们的IL代码吧:
       C#:
bubuko.com,布布扣
       IL:
bubuko.com,布布扣

      做到这儿,我突然想到一件事,哈哈,因为我看到以前的一位前辈给我讲singleton时说的两种模式,懒汉式和饿汉式,当时最纠结就是为了怕多线程访问这个单例模式,所以需要做很多判断,我突然想到,要是哪天我遇到一个项目需要用单例模式,哈哈,我就给特殊的component来处理这个单利模式,怎么处理,我们就把单例模式的构建写到类型构造函数,或者说我不单独设个组件来处理吧,就是写到当前这个类里也是一件很让人省心的事。不过这个值得考究,比较没验证过。

       why? 我建议说下类型构造器的工作模式,首先声明不是绝对的正确,只是一个大致的理解。
       首先,我们说了类型构造器的调用时CLR来完成的,CLR在调用一段代码时,这里我们暂且理解为函数吧,这个时候他会首先去检测这些代码引用了哪些类型。同时他会在AppDomain中检测类型是不是已经加载,如果没有加载那就回去加载这些类型,这个时候一旦我们定义了类型构造器,它就会来执行我们的类型构造器,不同的是,CLR为了避免对类型对象的破坏,对多线程的访问加了互斥线程同步锁,类型构造器的执行,在构造完类型对象后,在AppDomain中这个对象就会存在了,下一次再有对象需要这个类型是发现类型对象存在,CLR就不做调用类型构造器了,即使有多个多项调用这个类型构造器,但此时尚未构造完这个类型对象,我们上面说了会有锁机制来保证,一旦类型对象完成构建下面的对类型构建的操作就会直接返回。所以,这就是我投机取巧的立足点。
说道这里我突然想多嘴,我们知道Object有四个基本的方法,其中一个Gethashcode的方法,这个大概没多少人用过,其实这个和我们的类型构造没多少直接联系,说他是因为上面我说的了“CLR为了避免对类型对象的破坏 ”这一句,为什么这么说?原因是CLR认为把对象和hash结合有很多的好处,从内存的分配,从访问效率,从安全性(这个扯远了,呵呵)。我们发现实例每一个对象都有一个对应的hashcode值,我们做个试验:

   ----定义了一个空类
   class hashCodeTest
   {
   }

   -----实例化一些对象
   hashCodeTest test;
   for (int i = 0; i < 10; i++)
   {
        test=new hashCodeTest();
        Console.WriteLine(test.GetHashCode());
   }
   运行结果:    
bubuko.com,布布扣
我们发现每次运行hashcode都不一样,这是理所当然的,因为new出了不同对象,hashcode也反映了对象内存的分布,记住不是对应的地址,是对地址的一个映射,响应的equals方法我们经常强调,如果改写了equals方法那么也一定要记住改写gethashcode。为什么呢?因为equals是对对象值进行比较。与之相对的==是对对象应用的比较。Object默认的gethashcode如果类型构造器允许多次执行,就意味着类型对象可能改变它原来的内存地址,这将是一件非常可怕的事情,因为先前引用他的类将指向一个不可预计的地址。当然这与hashcode本身毫无关系,至少我们从hashcode的值上看出来的端倪。注意区分内存的分配和hashcode与之相映射的关系,这个hashcode是对地址的一个反映,或者说按照一套hash算法得出地址对应的hashcode值,因此如果说CLR版本变了,得出的hash值也不同的,所以不要认为只要值是相同的那么hashcode也一定是一样的,也不要实例化hashcode的值来做判定处理等,举个例子用户的验证、所谓的加密处理,因为hashcode是不可以逆的。有兴趣可以做个试验看看,定义一个字符串,然后起这个字符串的hashcode,你会发现只有是值相等hashcode的值也相当,但是如果你换个CLR版本就不一定了。这也是我在上面说hashcode只是一个内存地址按照hash算法的隐射地址而不是真实地址的原因。


本文出自 “碧雪青天” 博客,请务必保留此出处http://oversky.blog.51cto.com/1026601/1381291

构造器,布布扣,bubuko.com

构造器

原文:http://oversky.blog.51cto.com/1026601/1381291

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!