class A
C = 1
end
class B < A
class << self
def test1
puts C
end
end
def self.test2
puts C
end
def test3
puts C
end
end
=begin
主要来看下一下几种输出,看他们的结果都有什么样的?
p B.test1
p B.test2
我们来执行下这段代码输出就发现,会报错: in `test1': uninitialized constant Class::C (NameError)
为什么会报这个错误的?
我们会有疑问?
为什么在test2或者test3中可以直接使用C,在test1中就不能使用那?
p B.test2
p B.new.test3
p B.test3
我们来执行下这段代码输出的时候就发现,会报错: undefined method `test3' for B:Class (NoMethodError)
我们又会产生疑问了?
为什么test2 和 test3的调用方法不一样那?
先Hold的问题,听下面的一些讲解,你就会明白了。这块内容主要涉及到以下几点的内容
a. 关于类常量的作用域,以及使用范围
以大写字母打头的标识符是常量,对常量进行二次赋值解释器会提示警告,
而引用未被赋值的常量实抛出 NameError 异常。
在类、模块外部定义的常量属于 Object,可以使用“::常量名”
引用属于 Object 的常量,以“模块名/类名::常量名”的形式引用外部的常量
类内直接使用,继承类的类方法内直接使用类常量,继承类的类实例方法必须使用 类/模块::常量
下面就要说下什么是类方法?什么又是实例方法?
b. 关于类方法,形如一下格式:
def 类名.方法
***********
end
这个表示是属于类专用的方法,不属于类对象的方法, 使用:类名.方法
class B < A
def self.test2
puts C
end
end
同价于:
class B < A
def B.test2
puts C
end
end
调用:
B.test2
c. 实例方法
class B < A
def test3
puts C
end
end
这个是我们习惯性的写法,这个是属于类实例方法,属于类对象的专属方法,类不能直接使用。
调用用到时候必须先实例化,new一个对象,然后调用。
如: B.new.test3
d. 关于类对象追加方法用法
给特定的类对象追加方法或者属性,这些方法和属性是直接封装到一个类中,直接追加到对象中。
这个类没有特定的名字,所以不能像普通的类一样使用。
格式如下:
Class << obj
end
本例中使用如下:
class B < A
class << self
def test1
puts C
end
end
end
这个里面我们使用到了<< 和self, << 是追加的意思,self的含义:当前对象,或者是默认对象
这个虚拟类(元类 metaclass)的self指的的是什么那?
self这个在虚拟类中指的默认对象是:#<Class:B>
self这个在虚拟类中的test1方法中指的默认对象是:B,如同在class B中的self
这个是用到了ruby的单件类或叫metaclass 也有叫singletonclass。
这个类的执行环境就相当于不在Class B中了,虽然写在这个位置。从self可以看出他们的执行对象是不同的。
e. 关于继承
这个就不多讲了,A<B 就是A继承了B ,A 是B的子类,可以使用A的所有资源,A可以重写父类方法。如同java的继承。
Ruby是单继承的,但是也能实现多继承的可以实现的一切。。
使用Model模块,在类中include 模块 就能达到多继承的效果了。
现在我们再来看代码:
下面我们来分析下test1 test2 test3 三个方法:
我们主要来看下他的执行环境吧,即class执行的一个有效范围吧,即 self对象指的是什么东西?
test1: 是B的单例类的方法。 这个特殊类的执行环境是在B类外的。
test2: 是类方法,B继承了A,就继承了C,可以在类的方法(类方法和类实例方法)中使用。执行环境是Class B中
test3: 是B的类对象方法,执行环境是类B中:Class B ---> end
所以在test1中使用常量,就相当于在类外使用类常量了。
使用方式如下:A::C 或者B::C 或者self::C
为什么可以使用self::C那?
因为test1方法中的self 指的是:B 等价于 使用B::C,B继承A,写成A::C也是ok的
=end
关于self 类的应用
最新推荐文章于 2022-05-01 05:00:00 发布