在Ruby中,当一个类被调用方法未找到时,该类的method_missing(name,*args,&block)方法会被自动调用,通过这个黑科技,人们在ruby上实现了各种元编程技巧. 介绍Dynamic实现了与method_missing几乎一样的功能.然而事实上,它们差别还是挺大的. 先写2个例子吧,分别是scala,ruby实现类似的功能. import scala.language.dynamics import scala.io._ object Dispatch extends Dynamic { def selectDynamic(name:String):String = "Call Method: " + name def main(args:Array[String]){ println(Dispatch.SCALA); println(Dispatch.RUBY); val cls = Dispatch.getClass while(true){ println(cls.getMethod(StdIn.readLine).invoke(null)) } } } class Dispatch def method_missing(name,*args,&block) puts "Call Method: "+name.to_s end end ins = Dispatch.new ins.SCALA ins.RUBY ins.send(gets) while true 都是先尝试调用SCALA和RUBY方法,再循环读取用户输入,调用以输入值为名字的方法. 运行一下~
咦,java.lang.NoSuchMethodException,没有找到方法... 到底是为什么呢?看看scala编译后的字节码把. [shyling@archlinux:~]$ javap -c Dispatch 16-04-14 15:36 Compiled from "dynamic.scala" public final class Dispatch { public static void main(java.lang.String[]); Code: 0: getstatic #16 // Field Dispatch$.MODULE$:LDispatch$; 3: aload_0 4: invokevirtual #18 // Method Dispatch$.main:([Ljava/lang/String;)V 7: return public static java.lang.String selectDynamic(java.lang.String); Code: 0: getstatic #16 // Field Dispatch$.MODULE$:LDispatch$; 3: aload_0 4: invokevirtual #22 // Method Dispatch$.selectDynamic:(Ljava/lang/String;)Ljava/lang/String; 7: areturn } [shyling@archlinux:~]$ javap -c Dispatch\$.class 16-04-14 15:36 Compiled from "dynamic.scala" public final class Dispatch$ implements scala.Dynamic { public static final Dispatch$ MODULE$; public static {}; Code: 0: new #2 // class Dispatch$ 3: invokespecial #14 // Method "<init>":()V 6: return public java.lang.String selectDynamic(java.lang.String); Code: 0: new #18 // class scala/collection/mutable/StringBuilder 3: dup 4: invokespecial #19 // Method scala/collection/mutable/StringBuilder."<init>":()V 7: ldc #21 // String Call Method: 9: invokevirtual #25 // Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder; 12: aload_1 13: invokevirtual #25 // Method scala/collection/mutable/StringBuilder.append:(Ljava/lang/Object;)Lscala/collection/mutable/StringBuilder; 16: invokevirtual #29 // Method scala/collection/mutable/StringBuilder.toString:()Ljava/lang/String; 19: areturn public void main(java.lang.String[]); Code: 0: getstatic #39 // Field scala/Predef$.MODULE$:Lscala/Predef$; 3: aload_0 4: ldc #41 // String SCALA 6: invokevirtual #43 // Method selectDynamic:(Ljava/lang/String;)Ljava/lang/String; 9: invokevirtual #47 // Method scala/Predef$.println:(Ljava/lang/Object;)V 12: getstatic #39 // Field scala/Predef$.MODULE$:Lscala/Predef$; 15: aload_0 16: ldc #49 // String RUBY 18: invokevirtual #43 // Method selectDynamic:(Ljava/lang/String;)Ljava/lang/String; 21: invokevirtual #47 // Method scala/Predef$.println:(Ljava/lang/Object;)V 24: aload_0 25: invokevirtual #53 // Method java/lang/Object.getClass:()Ljava/lang/Class; 28: astore_2 29: getstatic #39 // Field scala/Predef$.MODULE$:Lscala/Predef$; 32: aload_2 33: getstatic #58 // Field scala/io/StdIn$.MODULE$:Lscala/io/StdIn$; 36: invokevirtual #61 // Method scala/io/StdIn$.readLine:()Ljava/lang/String; 39: iconst_0 40: anewarray #63 // class java/lang/Class 43: invokevirtual #67 // Method java/lang/Class.getMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method; 46: aconst_null 47: iconst_0 48: anewarray #4 // class java/lang/Object 51: invokevirtual #73 // Method java/lang/reflect/Method.invoke:(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object; 54: invokevirtual #47 // Method scala/Predef$.println:(Ljava/lang/Object;)V 57: goto 29 } 可以看到Dispatch.SCALA仅仅是被编译器翻译成了Dispatch.selectDynamic("SCALA"),其他的并没有什么黑科技.因为jvm本身没有提供类似method_missing的方法,所以...通过反射调用不存在的方法时,会抛出NoSuchMethodException. 假如我们想在jvm更贴近实现method_missing需要怎么做呢?
好像没有特别好的办法.
感觉都不如method_missing优雅啊.动态语言的优势么2333 (责任编辑:好模板) |