再顺手转回来免得以后找起来麻烦

[quote="star022"]Java代码 

findStatic( 

 TestMethodHandle1.class, // 方法所属类型(Class) 

 "hello", // 方法名 

 type // 由参数和返回值类型组成的“方法类型” 

); 


type// 由参数和返回值类型组成的“方法类型” 

“方法类型”这个参数设计得很失败, 

一个类中的方法,如果方法名和参数个数及类型一样,这个类能正确编译吗? 

其实MethodHandle最终只需要暴露类似这样一个静态方法即可: 

//方法如果没有返回值,为void 

MethodHandle.<T>invoke( 

 Class clazz, // 方法所属类型(Class) 

 String methodName, // 方法名 

 Object... params//方法参数,可以运行时确定参数个数及类型,定位到具体方法 

)



[/quote]
你的思路被局限在Java“语言”里了。JSR 292的主要服务对象是JVM上的动态语言,而不是Java。如果你了解JVM的spec而不只是Java的spec,你应该能理解Java字节码不是只能通过Java编译器来生成的。你可以把我之前回帖的那段完整引用一次:
[quote="RednaxelaFX"][quote="star022"]定位到一个java方法,其实只需要类型(Class),方法名及参数即可。[/quote]
对,说得一点也没错,所以MethodHandles的API就是这样的:
[quote]

findStatic(
    TestMethodHandle1.class, // 方法所属类型(Class)
    "hello",                 // 方法名
    type                     // 由参数和返回值类型组成的“方法类型”
);

[/quote]


如果只是要做Java的method overload resolution,当然只要参数类型不要返回值类型就够了,但了解class文件及JVM内部数据组织方式的话就会知道,方法的签名(signature)在class文件里是以方法描述符(method descriptor)的形式存在,而该描述符上是有返回值类型的。MethodHandles的API这么设计就是为了快,能更直接的访问VM里的信息,以最快的方式找到目标方法。[/quote]



如果那段文字仍然不能让你明白,那请看下面的例子。


首先要明确的是,在Java语言里,method overload只依赖于方法名和参数类型,不考虑返回值类型;仅在返回值类型不同的方法无法通过[b]Java编译器[/b]的编译。


但生成Java字节码的方式有很多:JVM上有非常多其它语言,它们的编译器都可以生成Java字节码;动态代理要生成字节码;再不行,手工生成字节码也是可以的。从JVM的角度看,无论字节码的来源是什么,只要符合class文件规范、只要加载成功,JVM就可以执行那些字节码。


这里我用bitescript来生成一个class文件,类名为TestMethodSameName,包括两个foo方法,它们只在返回值类型上不同:


require 'rubygems'
require 'bitescript'
include BiteScript

fb = FileBuilder.build(__FILE__) do
  public_class 'TestMethodSameName' do
    public_static_method 'foo', void, int do
      ldc 'TestMethodSameName.foo:(I)V'
      aprintln
      returnvoid
    end

    public_static_method 'foo', int, int do
      ldc 'TestMethodSameName.foo:(I)I'
      aprintln
      iload 0
      ireturn
    end

    public_static_method 'main', void, string[] do
      push_int 123
      invokestatic this, 'foo', [void, int]
      push_int 456
      invokestatic this, 'foo', [int, int]
      pop
      returnvoid
    end
  end
end

fb.generate do |filename, class_builder|
  File.open(filename, 'w') do |file|
    file.write(class_builder.generate)
  end
end



得到的class文件,内容如下:


Compiled from "test5.rb"
public class TestMethodSameName extends java.lang.Object{
public static void foo(int);
  Code:
   0:   ldc     #9; //String TestMethodSameName.foo:(I)V
   2:   getstatic       #15; //Field java/lang/System.out:Ljava/io/PrintStream;
   5:   swap
   6:   invokevirtual   #21; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   9:   return

public static int foo(int);
  Code:
   0:   ldc     #24; //String TestMethodSameName.foo:(I)I
   2:   getstatic       #15; //Field java/lang/System.out:Ljava/io/PrintStream;
   5:   swap
   6:   invokevirtual   #21; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
   9:   iload_0
   10:  ireturn

public static void main(java.lang.String[]);
  Code:
   0:   bipush  123
   2:   invokestatic    #28; //Method foo:(I)V
   5:   sipush  456
   8:   invokestatic    #30; //Method foo:(I)I
   11:  pop
   12:  return

}



如果用Java语法来写,就是:


public class TestMethodSameName {
    public static void foo(int i) {
        System.out.println("TestMethodSameName.foo:(I)V");
    }

    public static int foo(int i) {
        System.out.println("TestMethodSameName.foo:(I)I");
        return i;
    }

    public static void main(String[] args) {
        foo(123); // foo:(I)V
        foo(456); // foo:(I)I
    }
}



再次注意到这段代码用[b]Java编译器[/b]确实编译不了。但上面生成的字节码对JVM来说却是完全没问题的。执行结果输出如下:

[quote]TestMethodSameName.foo:(I)V 

TestMethodSameName.foo:(I)I[/quote]



这很好的说明了在深入到底层去挖掘MethodHandle时,指定返回值类型的必要性。


JDK原本包含的普通反射API之所以不需要指定返回值类型是因为它只是为Java语言服务的。如今的JSR 292则是为JVM上所有语言服务,主要目标是各种动态语言,但也不拒绝Java去使用它。



关于bitescript的用法,请参考[url=http://rednaxelafx.iteye.com/blog/400362]这一帖[/url]的例子。上面生成的class文件我也放在附件里了,不相信例子的输出结果的话请自己执行一下,眼见为实。