打开类
可以重新打开已经存在的类并进行动态修改,即便是标准类库也不例外
- 1
- 2
- 3
- 4
- 5
- 6
这种方式是不是很方便? 当然凡事都有利弊,带来方便的同时也给我们带来了一些问题:可能会对于类中已有的方法进行覆盖,为了修复这样的问题所使用的patch称为猴子补丁.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
所以,虽然打开类技术非常方便,但是由于若是乱用可能会导致很大的问题.
类与对象
1. 对象中有什么
- 1
- 2
- 3
- 4
- 5
- 6
-
实例变量
与一般静态语言不同,Ruby中的对象的类和它的实例变量没有关系,当给实例变量赋值时,它们才会产生.
obj.instance_variables #=>[]
obj.my_method
obj.instance_variables #=>[:@v]
-
方法
除了实例变量,对象还有方法,虽然可以利用methods方法查看到对象所拥有的方法,但实际上对象并没有存放这些方法,而是存放一个对自身类的引用.而这些方法存放在类中,称之为实例方法,与类方法截然不同.实例方法必须是类的实例才能调用,而类方法必须是类本身才能调用.
String.instance_methods == "abc".methods #=>true
String.methods == "abc".methods #=>false
总结: 一个对象的实例变量存在与对象本身,而一个对象的方法存在与对象自身的类.这也是为什么同一个类的对象共享者同样的方法,但不共享实例变量的原因.
2. 类
- 类自身也是对象
- 1
- 2
一个对象的方法也就是其类的实例方法,也就是说一个类的方法就是Class的实例方法
- 1
- 2
- 3
- 4
- 5
所有类最终都继承与Object,Object本身又继承与BasicObject, BasicObject是Ruby对象体系中的根结点.
- 1
- 2
- 3
- 4
- 5
- 6
所以,一个类不过是一个增加了三个方法的Module.类和模块基本上是一样的,绝大多数适用于类的情况也同样适用于模块,反之亦然.
- 1
- 2
- 3
上述代码的模型图如下:
load 与require
使用load(‘test.rb’)可引用外部代码, 但对于test.rb文件所定义的变量和类会落在当前作用域之外,而常量则会落在当前作用域之类,这样便会污染当前程序的命名空间,不过可使用load(‘test.rb’, true)强制其常量仅在自身范围内有效.
require() 方法与load()相似,但load可以执行代码,而require则是导入类库
总结:
类就是对象,只不过类名是常量[任何以大写字母开头的引用,包括类名和模块名].
方法调用
当调用一个方法时, Ruby会做两件事
1. 找到这个方法, 需要祖先链
2. 执行这个方法, 需要self
1.方法查找
-
接收者 : 即为调用方法所在的对象, 如
obj.method()
中,obj
即为接收者 -
祖先链 : 从当前类一直向上寻找超类直到找到
BasicObject
类所经过的路径,即为祖先链(亦包括模块).
方法查找: 首先在接收者的类中查找,然后一层层在祖先链中查找,直到找到该方法为止.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
当在一个类(或模块)中包含一个模块时,Ruby创建一个封装该模块的匿名类,并将其插入到祖先链中.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
Kernel模块
如果给Kernel模块增加一个方法,这个内核方法就对所有对象可用.
2.方法执行
- 探索self
每一行代码都会在一个当前对象中执行,可使用
self
关键字访问当前对象.当调用一个方法时,接收者就成为self, 这时所有的实例变量都是self 的实例变量,搜偶没有明确指明接收者的方法都在self上调用.
- 类定义与self
self通常由最后一个接受到方法的对象充当,但在类或模块定义中[任意方法定义之外], self由这个类或模块充当.
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 私有private
不能明确指定一个接收者来调用一个私有方法, 但可通过send方法破坏私有性
小结
- 对象由一组实例变量和一个类的引用组成
- 对象的方法存在与自身的类中,称之为实例方法
- 类本身是Class类的实例,类名即为常量
- Class类是Module的子类,一个模块是有一组方法组成的包.
- 常量像文件系统一样,按照树形结构组织, 其模块和类的名字扮演目录的角色, 其它普通常量则扮演文件的角色.
- 每一类都有一个祖先链, 从自己所属类开始直到BasicObject结束
- 当调用一个方法时,Ruby会先向右来找到所属类,然后沿着祖先链向上查找
- 每当类包含一个模块时, 该模块会被插入到祖先链中, 位于该类的正上方
- 当调用一个方法时, 接收者会扮演self角色
- 当定义一个模块或类时, 该模块或类扮演self角色
- 实例变量永远被认定为self的实例变量
- 任何没有明确指定接收者的方法调用,都是调用self的方法