ruby中的对象是类生成的,而类本身也是对象。ruby的顶级类是Object其余所有的类都直接或简介继承与Object。其中Class继承Module,Module继承Object,而所有的对象其实都是Class类的示例,这其中当然包括Object,Module,以及Class类本身。这便产生了一些很有趣的事情,这些等下在慢慢道来。这里先说说ruby内部实现中的一些变量,注意类对象与类的对象的区别,类对象指的是类本身因为类也是对象所以称为类对象这是为了区别与普通对象而称呼的,而类的对象是指由这个类所构造出来的对象。
ruby是由c语言实现的且ruby是纯面向对象的语言,在ruby中一切都是对象。在内部实现中ruby任何对象都有以下三个变量:
1.klass指针,因为class是ruby关键词,所以就变成了klass...。对象中的klass指针指向这个对象所属的类。
2.iv_tbl,是一个保存该对象实例变量的哈希信息。
3.flags,顾名思义这是对象的标志信息变量,用以标志对象是否被污染是否被回收是否被冻结等信息。
如果对象是类(Class)或者是模块(Module)(ruby中一切都是对象),出了以上三个变量外,还有以下两个量。
1.super指针,这个一看就知道是指向这个类的父类,有人可能会糊涂,类有父类这没错,模块不能继承难道模块也有父类?的却是有的。模块虽然不可以继承,但一个模块却可以包含(include)另外一个模块。当模块包含一个模块时此模块的super指针就指向被包含模块所生成的虚拟类也或者是说代理类(模块被包含都会生成代理类以便模块插入继承链中)
2.m_tbl,既然上面有个iv_tbl是实例变量表,那么这个肯定是实例方法表。
有以上信息可知,第一类跟模块也是对象包含普通对象所有的特征。但类与模块也是特殊的对象除了普通对象的特征外还有作为类与模块的特别的特征。其次实例变量都是保存在对象自己的数据结构中,而方法都是保存在类中,并且类中保存的方法只有实例方法。那么类方法呢?其实类方法也是实例方法,是类的实例方法,保存在类的单例类中。对象在调用方法时,首先沿着对象klass(klass所指的类不一定是直接生成这个对象的类也有可能个是这个对象的单例类)所指的类的方法表中(m_tbl)中寻找方法,若没找到就通过super依次沿着继承链寻找父类跟祖先类的方法表寻找此方法,知道找到所调用的方法或者沿着继承链到Object类。如果在Object中也没有此方法的定义则又从头开始按照上述方法寻找method_missing这个方法。
继续开头讲得那个有趣的事情。Class是类也是对象Class是本身的对象,Class的klass指针指向自己。由上述我们可知方法都是保存在类中的,当Class作为一个对象时他的方法保存在哪里?自然是保存Class对象所属的类中也就是Class类本身当中。但如果Class作为类通过Class.new生存一个普通对象时此时Class类中保存的也还是实例方法。但Class类的类方法呢? 按道理Class类方法也就Class这个类对象的实例方法应该保存在Class这个类对象的单例类中。先看一个例子:
我们重新打开Class类定义一个方法
- class Class
- def show
- puts "hello"
- end
- end
- lass.new.show
输出:hello
- Class.show
输出:hello
上述例子Class类中定义的实例方法也成了类方法。为何?其实也不难理解,因为Class做为类时保存类的实例方法,由Class类生成的普通对象即Class.new这个对象的klass指针是指向Class这个类的,根据方法寻找的规则所以Class.new.show是调用Class类的实例方法。而因为Class类也是其本身的对象所以他的klass指针也是指向本身,所以通过Class.show这中方式调用Class类的类方法时还是调用的同一个方法。这一切归根结底是因为类也是对象在作为对象时是与普通对象并无差别,而所谓的类方法其实也是实例方法只不过是另外一个类的实例方法而已。所以Class类是对象还是先是类呢?...
但类对象与普通对象也不是完全是一样的,请看下面例子:
- irb(main):022:0> class Class
- irb(main):023:1> @@a="a"
- irb(main):024:1> @b="b"
- irb(main):025:1> def show
- irb(main):026:2> puts @@a
- irb(main):027:2> puts @b
- irb(main):028:2> end
- irb(main):029:1> end
- => nil
- irb(main):030:0> Class.show
- a
- b
- => nil
- irb(main):031:0> Class.new.show
- a
- > nil
还是重新打开了Class类,只不过在类中定义了两个变量,一个类变量@@a,一个实例变量@b,为何同一个方法却输出不同的结果呢?因为@b是在类域中定义的而不是方法域中定义的所以@b是Class类对象的实例变量,所以Class.show能够打印出@b的值,而Class.new.show方法是不能打印出@b的值,因为实例变量保存在对象里其他的任何对象都无法访问到。类变量与类实例变量看起来很相似,但其实是有区别的,它们的区别就是类变量对这个类所生成的所有对象是也可见并且共享的,这也是它们唯一的区别。在类对象本身它们并无二致都可看作类的实例变量。
本文出自 “梦想成就未来” 博客,请务必保留此出处http://consy.blog.51cto.com/2212530/399864