JRuby的类重定义……为什么不行?

在jirb里想试试这个的:
class java.lang.Integer
def +(rhs)
self.int_value() + rhs
end
end

但是jirb总是提示self.int_value() + rhs那行有错。到底是为什么呢?

我也就是想这样而已……
irb(main):001:0> i = java.lang.Integer.new(1) # OK
irb(main):002:0> i
=> #<Java::JavaLang::Integer:0x1fbc355 @java_object=1>
irb(main):003:0> i.java_class
=> java.lang.Integer
irb(main):004:0> i.int_value
=> 1
irb(main):005:0> i + 2 # not impl'd
=> 3 # what I'd like to see


结果我发现我犯了个超低级的错误。JRuby实现java.lang.Integer这样的类型访问实际上是通过method_missing机制,先是对java这个[b]方法[/b]进行调用,方法不存在而通过method_missing机制,转换成一个值返回过来;然后对这个[b]返回值[/b]调用其lang[b]方法[/b](或者还是说“发送"lang"消息”更合适?),不存在,于是在method_missing里做了点手脚来找到对应的package并返回[b]又一个值[/b],再调用Integer方法,同样是不存在然后通过method_missing找到对应的Java类。

在jirb里试试这个就知道上面说的是什么了:
irb(main):001:0> java
=> Java::Java
irb(main):002:0> java()
=> Java::Java
irb(main):003:0> com
=> Java::Com
irb(main):004:0> com().sun()
=> Java::ComSun

这里的java啊com啊什么的都[color=red]不是变量[/color],而是不存在的方法而已。

于是,java.lang.Integer只是个会返回一个值的一连串方法调用。Java::JavaLang::Integer才是这个Java类在JRuby里的名字。形式是:
[quote]Java::FullPackageNameInCamelCase::ClassName[/quote]

明白了这点之后,只要把上面的代码改一句就行:
irb(main):001:0> class Java::JavaLang::Integer # 改了这里
irb(main):002:1> def +(rhs)
irb(main):003:2> self.int_value + rhs
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> i = java.lang.Integer.new 2
=> #<Java::JavaLang::Integer:0x7efa96 @java_object=2>
irb(main):007:0> i + 3
=> 5


T T 这种集成方法还是稍微surprise了一下。
不过回过头来想想,IronRuby/DLR的做法跟这个在表现上非常相似,但具体做法不同。JRuby主要通过method_missing机制,而IronRuby/dlr则通过注入全局变量:可以在host里为脚本运行环境注入一个名为System的NamespaceTracker类型全局变量,它会自动找到System下面的各个类以及各个子命名空间。我还是玩DLR的时间更多些,对IronRuby也比对JRuby更熟悉些。可惜现在的IronRuby离真正“能用”差得还好远。
在John Lam的blog上的一篇文章,[url=http://www.iunknown.com/2008/03/dynamic-silve-2.html]Dynamic Silverlight Part 3: Integrating Silverlight with ASP.NET MVC[/url]里,就有这种要在IronRuby的代码里复写.NET原有类型的方法的使用场景:
silverlight.rb:
class UIElement
alias_method :old_render_transform_origin=,
:render_transform_origin=

def render_transform_origin=(point)
self.old_render_transform_origin = Point.new(point.first, point.last)
end
end

类名直接就UIElement了(多好 T T
UIElement是Silverlight/WPF的一个类。这里是要给RenderTransformOrigin方法写一个adaptor,让它的参数类型从WPF的Point改变为Ruby的数组,让整个类用起来更“Ruby”。很有趣。
当然前面是有相应的require的。JRuby在做了合适的require之后也能达到类似的效果。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值