Ruby中的反射(Reflection)应用实例

在Java语言中,提供了发射机制,通过发射机制可以通过字符串构造出这个对象,可以获取对象的所有方法(包括私有方法),可以调用私有方法,可以更改成员变量的值(包括私有的成员变量)。
Ruby也是面向对象的高级语言,当然也提供了反射机制,今天我们讨论通过类名称构造类对象的功能。

一、通过类名称构造类对象

我们先看普通的构造:

代码如下:

module ModuleA

#the class name, later we will use it to create the corresponding object

CLASS_NAME_OF_WOOD = "ModuleA::Wood"

CLASS_NAME_OF_WOODDESK = "ModuleA::WoodDesk"

CLASS_NAME_OF_WOODCHAIR = "ModuleA::WoodChair"

class Wood

def initialize

@desc = "I am a primal wood"

end

def say

puts @desc

end

end

class WoodDesk < Wood

def initialize

@desc = "I am a desk made of wood"

end

def say_private

puts "actually, i have some bug but no public"

end

public :say

private :say_private

end

class WoodChair < Wood

def initialize

@desc = "I am a chair made of wood"

end

def say_private

puts "I Want get married with a WoodDesk..."

end

def smile

puts "ha hah hah haha ...."

end

public :say

private :say_private, :smile

end

end

定义了一个基础类Wood,有两个子类:WoodDesk, WoodChair,子类有分别有一个私有方法 say_private。
我们new出对象来执行:

代码如下:

#the normal initailze

wood = ModuleA::Wood.new

wood.say

desk = ModuleA::WoodDesk.new

desk.say

chair = ModuleA::WoodChair.new

chair.say

#try call the private method

puts "desk respond to say_private? #{desk.respond_to? :say_private}"

desk.say_private if desk.respond_to? :say_private

上面代码,执行public方法say,然后尝试执行private方法 say_private,执行先check是否能够执行,返回结果是不能执行,desk.respond_to? :say_private返回false:

代码如下:

I am a primal wood

I am a desk made of wood

I am a chair made of wood

desk respond to say_private? false

好,现在我们通过反射机制来构造对象,并尝试执行其私有方法。

我们注意到模块的定义中有三个常量,定义的是类名称,


代码如下:

#the class name, later we will use it to create the corresponding object

CLASS_NAME_OF_WOOD = "ModuleA::Wood"

CLASS_NAME_OF_WOODDESK = "ModuleA::WoodDesk"

CLASS_NAME_OF_WOODCHAIR = "ModuleA::WoodChair"

下面会通过这三个变量来理解Module.constants方法。

下面代码片段,基于上面的类定义:

代码如下:

#get all module constants

obj_list = Array.new

tmp_const_sym_list = ModuleA.constants

tmp_const_sym_list.each do | sym |

obj_list << ModuleA.const_get(sym)

puts "calss = #{sym.class}, value = #{sym}"

end

我们注意到 ModuleA.constants,这个方法是Module模块中的,其作用是返回模块中所有常量的Symbol对象。我们看结果输出:

代码如下:

calss = Symbol, value = CLASS_NAME_OF_WOOD

calss = Symbol, value = CLASS_NAME_OF_WOODDESK

calss = Symbol, value = CLASS_NAME_OF_WOODCHAIR

calss = Symbol, value = Wood

calss = Symbol, value = WoodDesk

calss = Symbol, value = WoodChair

从结果中看到,定义的三个常量和类名称都被返回了。所以注意:Ruby中的常量是包含定义的常量(变量)和类名称,注意他们都是Symbol对象。。

不过我们是需要根据类名称构造类对象,那么那三个常量就是没用的,需要删除。我们通过正则表达式匹配名字,来过滤。上面的代码修改一下:

代码如下:

#get all module constants

sym_list = Array.new

tmp_const_sym_list = ModuleA.constants

tmp_const_sym_list.each do | sym |

puts "calss = #{sym.class}, value = #{sym}"

sym_list << ModuleA.const_get(sym) if /^Wood\w*/ =~ sym.to_s

end

sym_list << ModuleA.const_get(sym) if /^Wood\w*/ =~ sym.to_s,仅保存以Wood开头的symbol,这样我们就过滤掉了那三个常量。

找都类名称之后,开始构造对象:

代码如下:

#create object from symbol

obj_list = Array.new

sym_list.each do | sym |

obj = sym.new

obj_list << obj

puts "create the object: #{obj}"

end

begin

obj_list.each do | wood |

wood.say

end

调用Symbol的new方法构造出次对象(sym.new),然后我们调用对象的say方法:

代码如下:

create the object: #

create the object: #

create the object: #

I am a primal wood

I am a desk made of wood

I am a chair made of wood

达到了我们预期的结果。

二、操作成员变量和私有方法

使用过Java反射的同学们都知道,有了对象之后,操作成员变量和私有方法也就不在话下了。
Ruby中也是一样。

先看操作成员变量的例子。我们尝试更改一个成员变量的值。(接着上一片文章的代码)

代码如下:

#manpulate instance variables

first_wood = obj_list.first

first_wood.instance_variables.each do | var |

#get the instance variable

puts "class of var = #{var.class}, value of var = #{var}"

var_value = first_wood.instance_variable_get(var)

puts "class of var_value = #{var_value.class}, value of var_value = #{var_value}"

#set the new value of instance varialbe

first_wood.instance_variable_set(var, var_value + "...and i was changed.")

first_wood.say

end

1、first_wood.instance_variables.each,我们得到一个Wood对象,然后调用其instance_variables方法得到所有成员变量的名称(Symbol对象)。
2、然后,调用对象的first_wood.instance_variable_get方法,传递成员变量名称,得到成员变量对象。
3、最后,我们通过first_wood.instance_variable_set,改变这个成员变量的值。
代码运行结果:

代码如下:

class of var = Symbol, value of var = @desc

class of var_value = String, value of var_value = I am a primal wood

I am a primal wood...and i was changed.

再看调用私有方法:

代码如下:

#call private method

last_wood = obj_list.last

last_wood.method(:say_private).call

很简单,如果你知道方法名称,调用last_wood.method传入方法名,就可以得到一个Method对象,然后调用Method对象的call方法,结果是私有方法输出的内容:

代码如下:

I Want get married with a WoodDesk...

普通场景下用不到修改成员变量和调用私有方法,因为这是违反了面向对象的封装原则的,那么反射在什么场景下有用呢?从我个人经验来说我觉得两个地方有用:
1)单元测试。
2)面向方面编程。
这两种场景都需要调用私有方法或替换成员变量的值。

你觉得呢?

(0)

相关推荐

  • C# 反射(Reflection)的用处分析

    乱侃 作为一名新手,一直没有勇气去写一篇分享.原因有很多:诸如:自己水平有限.语言表达不准确.写出的东西没有一点技术点被人嘲笑.今天在公司听了内部员工的一个分享,其中最重要的一点是:提升自身水平的最佳的途径就是--交流.不管你是通过什么途径,交流也好.整理成文字分享也好等等都是很好的方式.故此,今天献丑写一篇自己的心得分享,欢迎各路大神的指教!    需求背景 今天接到的需求里面有个这样的需求,如下图所示,需要打印出如Excel内容呈现的单据.     动手操作第一版本 而为了实现这个业务需要涉

  • c#反射机制学习和利用反射获取类型信息

    1..NET可执行应用程序结构 程序代码在编译后生成可执行的应用,我们首先要了解这种可执行应用程序的结构. 应用程序结构分为应用程序域-程序集-模块-类型-成员几个层次,公共语言运行库加载器管理应用程序域,这种管理包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局. 程序集包含模块,而模块包含类型,类型又包含成员,反射则提供了封装程序集.模块和类型的对象.我们可以使用反射动态地创建类型的实例,将类型绑定到现有对象或从现有对象中获取类型,然后调用类型的方法或访问其字段

  • C#利用反射来判断对象是否包含某个属性的实现方法

    本文实例展示了C#利用反射来判断对象是否包含某个属性的实现方法,对于C#程序设计人员来说有一定的学习借鉴价值. 具体实现代码如下: /// <summary> /// 利用反射来判断对象是否包含某个属性 /// </summary> /// <param name="instance">object</param> /// <param name="propertyName">需要判断的属性</par

  • C#反射技术的简单操作(读取和设置类的属性)

    要想对一个类型实例的属性或字段进行动态赋值或取值,首先得得到这个实例或类型的Type,微软已经为我们提供了足够多的方法. 首先建立一个测试的类 复制代码 代码如下: public class MyClass { public int one { set; get; } public int two { set; get; } public int five { set; get; } public int three { set; get; } public int four { set; ge

  • PHP的反射类ReflectionClass、ReflectionMethod使用实例

    PHP5 具有完整的反射API,添加对类.接口.函数.方法和扩展进行反向工程的能力. 反射是什么? 它是指在PHP运行状态中,扩展分析PHP程序,导出或提取出关于类.方法.属性.参数等的详细信息,包括注释.这种动态获取的信息以及动态调用对象的方法的功能称为反射API.反射是操纵面向对象范型中元模型的API,其功能十分强大,可帮助我们构建复杂,可扩展的应用. 其用途如:自动加载插件,自动生成文档,甚至可用来扩充PHP语言. PHP反射api由若干类组成,可帮助我们用来访问程序的元数据或者同相关的注

  • c#反射调用方法示例

    获取方法的相关信息的两种形式 反射是一种允许用户获得类信息的C#功能,Type对象映射它代表的底层对象: 在.Net 中, 一旦获得了Type对象,就可以使用GetMethods()方法获取此类型支持的方法列表:该方法的两种形式: MethodInfo [] GetMethods() MethodInfo [] GetMethods(BindingFlags bindingflas)  :它的参数带有一些限制 BindingFlags  是一个枚举 枚举成员 [DeclaredOnly,Inst

  • PHP反射类ReflectionClass和ReflectionObject的使用方法

    PHP中的扩展反射类,该扩展用来分析php程序,导出或提取出关于类.方法.属性.参数等的详细信息,包括注释.看一个这样的问题,php类的成员变量没有在类中声明,而是在函数中声明,有什么不同? 复制代码 代码如下: class test{    private $name;    private $sex;    function __construct(){        $this->aaa='aaa';    }} $test=new test(); $reflect=new Reflect

  • C#中使用反射获取结构体实例及思路

    复制代码 代码如下: static void Main(string[] args){    Type type = typeof(MyObject);    object obj = type.GetConstructor(Type.EmptyTypes).Invoke(null);    Console.WriteLine(obj);} class MyObject{ } 之前我一直没有发现原来结构是不可以这样实例化的 换种方式,似乎结构体使用反射无法得到其构造函数ConstructorIn

  • C#反射(Reflection)对类的属性get或set值实现思路

    近段时间,有朋友叫Insus了解一下反射(Reflection)方面的知识,反射提供了封装程序集.模块和类型的对象(Type类型).可以使用反射动态创建类型的实例,将类型绑定到现有对象,或从现有对象获取类型并调用其方法或访问其字段和属性.如果代码中使用了属性,可以利用反射对它们进行访问. 下面的例子,是Insus练习对一个类别的属性进行set和get值. 首先写一个类,再写一个可读写的属性: 复制代码 代码如下: using System; using System.Collections.Ge

  • Ruby中的反射(Reflection)应用实例

    在Java语言中,提供了发射机制,通过发射机制可以通过字符串构造出这个对象,可以获取对象的所有方法(包括私有方法),可以调用私有方法,可以更改成员变量的值(包括私有的成员变量).Ruby也是面向对象的高级语言,当然也提供了反射机制,今天我们讨论通过类名称构造类对象的功能. 一.通过类名称构造类对象 我们先看普通的构造: 复制代码 代码如下: module ModuleA #the class name, later we will use it to create the correspondi

  • Ruby中对一元操作符重载实例

    一元操作大家都知道,就是表达式的操作符只有一个输入值.这个在C和Java中都很常见.今天我们要探讨一下Ruby中的一元操作符重载. 一元操作符有:+ – * ! & 等,为了避免与数值的 + – 混淆,重载一元操作符,要在后面加上一个 @ 操作符. 1. 一个简单的一元操作符重载例子:-@ 操作符 我们以String类为例子.String默认没有定义 – 操作符: 复制代码 代码如下: 1.9.3p125 :027 > a = "Hello" => "He

  • PHP 反射(Reflection)使用实例

    PHP Reflection是用于获取类.扩展.方法.函数.对象.参数.属性的详细信息. ReflectionClass类获取类相关信息,如获取属性.方法.文档注释等. <?php class Person { /** * For the sake of demonstration, we"re setting this private */ private $_allowDynamicAttributes = false; /** type=primary_autoincrement *

  • 实例讲解Java编程中数组反射的使用方法

    什么是反射 "反射(Reflection)能够让运行于JVM中的程序检测和修改运行时的行为."这个概念常常会和内省(Introspection)混淆,以下是这两个术语在Wikipedia中的解释: 内省用于在运行时检测某个对象的类型和其包含的属性: 反射用于在运行时检测和修改某个对象的结构及其行为. 从它们的定义可以看出,内省是反射的一个子集.有些语言支持内省,但并不支持反射,如C++. 内省示例:instanceof 运算符用于检测某个对象是否属于特定的类. if (obj inst

  • C#中的反射(System.Reflection)

    一.获取程序集Assembly 1.获取当前运行的程序集 System.Reflection.Assembly[] asm = AppDomain.CurrentDomain.GetAssemblies(); // Assembly b = Assembly.GetExecutingAssembly(); 2.获取指定文件的程序集:Load,LoadFrom,LoadFile方法. Assembly c = Assembly.Load("mscorlib.dll");//如果你引用了程

  • java中利用反射调用另一类的private方法的简单实例

    我们知道,Java应用程序不能访问持久化类的private方法,但Hibernate没有这个限制,它能够访问各种级别的方法,如private, default, protected, public. Hibernate是如何实现该功能的呢?答案是利用JAVA的反射机制,如下: import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class ReflectDemo {

  • 实例讲解Ruby中的五种变量

    Ruby 全局变量 全局变量以 $ 开头.未初始化的全局变量的值为 nil,在使用 -w 选项后,会产生警告. 给全局变量赋值会改变全局状态,所以不建议使用全局变量. 下面的实例显示了全局变量的用法. #!/usr/bin/ruby $global_variable = 10 class Class1 def print_global puts "Global variable in Class1 is #$global_variable" end end class Class2 d

  • 关于Spring Bean实例过程中使用反射和递归处理的Bean属性填充问题

    一.前言 超卖.掉单.幂等,你的程序总是不抗揍! 想想,运营已经对外宣传了七八天的活动,满心欢喜的等着最后一天页面上线对外了,突然出现了一堆异常.资损.闪退,而用户流量稍纵即逝,最后想死的心都有! 就编程开发来讲,丢三落四.乱码七糟,可能这就是大部分初级程序员日常开发的真实写照,在即使有测试人员验证的情况下,也会出现带Bug上线的现象,只不过是当时没有发现而已!因为是人写代码,就一定会有错误,即使是老码农 就程序Bug来讲,会包括产品PRD流程上的Bug.运营配置活动时候的Bug.研发开发时功能

  • Golang 中反射的应用实例详解

    目录 引言 Golang类型设计原则 Golang 中为什么要使用反射/什么场景可以(应该)使用反射 举例场景: 反射的基本用法 反射的性能分析与优缺点 测试反射结构体初始化 测试结构体字段读取/赋值 测试结构体方法调用 优缺点 反射在 okr 中的简单应用 结论 引言 首先来一段简单的代码逻辑热身,下面的代码大家觉得应该会打印什么呢? type OKR struct { id int content string } func getOkrDetail(ctx context.Context,

  • Go语言中使用反射的方法

    本文实例讲述了Go语言中使用反射的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: // Data Model type Dish struct {   Id  int   Name string   Origin string   Query func() } 创建实例如下: 复制代码 代码如下: shabushabu = Dish.new shabushabu.instance_variables # => [] shabushabu.name = "Shabu-S

随机推荐