Java反射基础(三)--Methods对象的使用

来源:互联网 发布:淘宝女用催情药 编辑:程序博客网 时间:2024/06/06 09:08

Method

原文地址:http://docs.oracle.com/javase/tutorial/reflect/member/method.html


1.获得方法类型信息


一个方法的声明包括方法名,修饰符, 参数, 和返回类型,同时还有一些方法可能抛出的异常. 类 java.lang.reflect.Method 提供了一种方式让我们可以得到方法的这些信息.

实例程序  MethodSpy 展示了枚举一个类中所有的方法,并返回指定方法的相关信息.

import java.lang.reflect.Method;import java.lang.reflect.Type;import static java.lang.System.out;public class MethodSpy {    private static final String  fmt = "%24s: %s%n";    // for the morbidly curious    <E extends RuntimeException> void genericThrow() throws E {}    public static void main(String... args) {try {    Class<?> c = Class.forName(args[0]);    Method[] allMethods = c.getDeclaredMethods();    for (Method m : allMethods) {if (!m.getName().equals(args[1])) {    continue;}out.format("%s%n", m.toGenericString());out.format(fmt, "ReturnType", m.getReturnType());out.format(fmt, "GenericReturnType", m.getGenericReturnType());Class<?>[] pType  = m.getParameterTypes();Type[] gpType = m.getGenericParameterTypes();for (int i = 0; i < pType.length; i++) {    out.format(fmt,"ParameterType", pType[i]);    out.format(fmt,"GenericParameterType", gpType[i]);}Class<?>[] xType  = m.getExceptionTypes();Type[] gxType = m.getGenericExceptionTypes();for (int i = 0; i < xType.length; i++) {    out.format(fmt,"ExceptionType", xType[i]);    out.format(fmt,"GenericExceptionType", gxType[i]);}    }        // production code should handle these exceptions more gracefully} catch (ClassNotFoundException x) {    x.printStackTrace();}    }}

实例输入及其输出:

$ java MethodSpy java.lang.Class getConstructorpublic java.lang.reflect.Constructor<T> java.lang.Class.getConstructor  (java.lang.Class<?>[]) throws java.lang.NoSuchMethodException,  java.lang.SecurityException              ReturnType: class java.lang.reflect.Constructor       GenericReturnType: java.lang.reflect.Constructor<T>           ParameterType: class [Ljava.lang.Class;    GenericParameterType: java.lang.Class<?>[]           ExceptionType: class java.lang.NoSuchMethodException    GenericExceptionType: class java.lang.NoSuchMethodException           ExceptionType: class java.lang.SecurityException    GenericExceptionType: class java.lang.SecurityException

它的实际定义代码为:

public Constructor<T> getConstructor(Class<?>... parameterTypes)


第一点需要注意的是.这里的返回和参数类型都是泛型Method.getGenericReturnType() 会首先在查询类中的属性签名,如果找到了,那就返回该类型.如果没有找到,该方法会去调用 Method.getReturnType() ,它的返回值便是定义该泛型时的所使用过的值.

第二点需要注意的是,最后一个参数,  parameterType,是一个可变数量的参数. 它被标识为一个一维数组.如果要区别这个和一个显示声明为数组的参数的话,可以使用方法 Method.isVarArgs().


接下来的示例展示了一个返回值为泛型的例子:

$ java MethodSpy java.lang.Class castpublic T java.lang.Class.cast(java.lang.Object)              ReturnType: class java.lang.Object       GenericReturnType: T           ParameterType: class java.lang.Object    GenericParameterType: class java.lang.Object

对于返回值是泛型的 Class.cast() 的方法,使用反射之后得到它的返回值是java.lang.Object. 这是因为在编译时期所有的跟泛型有关的信息都会被擦除. T的擦除被定义为CLass:

public final class Class<T> implements ..


因此T被取代使用向上转型原则.在这个示例中便是java.lang.Object了.

最后一个示例程序展示了一个输出一个多次重载的方法的例子:

$ java MethodSpy java.io.PrintStream formatpublic java.io.PrintStream java.io.PrintStream.format  (java.util.Locale,java.lang.String,java.lang.Object[])              ReturnType: class java.io.PrintStream       GenericReturnType: class java.io.PrintStream           ParameterType: class java.util.Locale    GenericParameterType: class java.util.Locale           ParameterType: class java.lang.String    GenericParameterType: class java.lang.String           ParameterType: class [Ljava.lang.Object;    GenericParameterType: class [Ljava.lang.Object;public java.io.PrintStream java.io.PrintStream.format  (java.lang.String,java.lang.Object[])              ReturnType: class java.io.PrintStream       GenericReturnType: class java.io.PrintStream           ParameterType: class java.lang.String    GenericParameterType: class java.lang.String           ParameterType: class [Ljava.lang.Object;    GenericParameterType: class [Ljava.lang.Object;


2.获得方法的参数名称


我们可以通过 java.lang.reflect.Executable.getParameters.方法获得任何方法和构造函数的形式参数的名称.(Method类和Constructor类都继承Executable类,因此他们都继承了方法Executable.getParameters.) 然而,默认情况下.class文件并不会存储形式参数名称.

如果想要保留形参形成,我们需要编译源码使用-parameters 选项.

实例程序 MethodParameterSpy 展示了如果获取一个指定类的所有方法和构造函数的形式参数的名称.实例同时还展示出一些关于参数的其他信息.

MethodParameterSpy源码:

/* * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * *   - Redistributions of source code must retain the above copyright *     notice, this list of conditions and the following disclaimer. * *   - Redistributions in binary form must reproduce the above copyright *     notice, this list of conditions and the following disclaimer in the *     documentation and/or other materials provided with the distribution. * *   - Neither the name of Oracle or the names of its *     contributors may be used to endorse or promote products derived *     from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import java.lang.reflect.*;import java.util.function.*;import static java.lang.System.out; public class MethodParameterSpy {         private static final String  fmt = "%24s: %s%n";     // for the morbidly curious    <E extends RuntimeException> void genericThrow() throws E {}         public static void printClassConstructors(Class c) {        Constructor[] allConstructors = c.getConstructors();        out.format(fmt, "Number of constructors", allConstructors.length);        for (Constructor currentConstructor : allConstructors) {            printConstructor(currentConstructor);        }          Constructor[] allDeclConst = c.getDeclaredConstructors();        out.format(fmt, "Number of declared constructors",            allDeclConst.length);        for (Constructor currentDeclConst : allDeclConst) {            printConstructor(currentDeclConst);        }              }         public static void printClassMethods(Class c) {       Method[] allMethods = c.getDeclaredMethods();        out.format(fmt, "Number of methods", allMethods.length);        for (Method m : allMethods) {            printMethod(m);        }            }         public static void printConstructor(Constructor c) {        out.format("%s%n", c.toGenericString());        Parameter[] params = c.getParameters();        out.format(fmt, "Number of parameters", params.length);        for (int i = 0; i < params.length; i++) {            printParameter(params[i]);        }    }         public static void printMethod(Method m) {        out.format("%s%n", m.toGenericString());        out.format(fmt, "Return type", m.getReturnType());        out.format(fmt, "Generic return type", m.getGenericReturnType());                         Parameter[] params = m.getParameters();        for (int i = 0; i < params.length; i++) {            printParameter(params[i]);        }    }         public static void printParameter(Parameter p) {        out.format(fmt, "Parameter class", p.getType());        out.format(fmt, "Parameter name", p.getName());        out.format(fmt, "Modifiers", p.getModifiers());        out.format(fmt, "Is implicit?", p.isImplicit());        out.format(fmt, "Is name present?", p.isNamePresent());        out.format(fmt, "Is synthetic?", p.isSynthetic());    }         public static void main(String... args) {                 try {            printClassConstructors(Class.forName(args[0]));            printClassMethods(Class.forName(args[0]));        } catch (ClassNotFoundException x) {            x.printStackTrace();        }    }}

下面的输出显示了类 ExampleMethods的方法和构造函数的形参名称.(注意:记得使用-parameters选项编译ExmapleMethods)

Number of constructors: 1Constructor #1public ExampleMethods()Number of declared constructors: 1Declared constructor #1public ExampleMethods()Number of methods: 4Method #1public boolean ExampleMethods.simpleMethod(java.lang.String,int)             Return type: boolean     Generic return type: boolean         Parameter class: class java.lang.String          Parameter name: stringParam               Modifiers: 0            Is implicit?: false        Is name present?: true           Is synthetic?: false         Parameter class: int          Parameter name: intParam               Modifiers: 0            Is implicit?: false        Is name present?: true           Is synthetic?: falseMethod #2public int ExampleMethods.varArgsMethod(java.lang.String...)             Return type: int     Generic return type: int         Parameter class: class [Ljava.lang.String;          Parameter name: manyStrings               Modifiers: 0            Is implicit?: false        Is name present?: true           Is synthetic?: falseMethod #3public boolean ExampleMethods.methodWithList(java.util.List<java.lang.String>)             Return type: boolean     Generic return type: boolean         Parameter class: interface java.util.List          Parameter name: listParam               Modifiers: 0            Is implicit?: false        Is name present?: true           Is synthetic?: falseMethod #4public <T> void ExampleMethods.genericMethod(T[],java.util.Collection<T>)             Return type: void     Generic return type: void         Parameter class: class [Ljava.lang.Object;          Parameter name: a               Modifiers: 0            Is implicit?: false        Is name present?: true           Is synthetic?: false         Parameter class: interface java.util.Collection          Parameter name: c               Modifiers: 0            Is implicit?: false        Is name present?: true           Is synthetic?: false


MethodParameterSpy 实例程序使用了Parameter类中的这些方法:

1.getType: 返回该参数被声明时的类型所对应的Class对象.

2.getName: 返回该参数的名称.如果这个参数的名称在.class文件中可以找到,那么就返回该名称.如果没有找到,

那么会自动生成一个名称,argN.其中N是参数的索引.

作为一个示例,不适用-parameters选项编译ExampleMethods源码.那么MethodParameterSpy将会打印出如下信息:

public boolean ExampleMethods.simpleMethod(java.lang.String,int)             Return type: boolean     Generic return type: boolean         Parameter class: class java.lang.String          Parameter name: arg0               Modifiers: 0            Is implicit?: false        Is name present?: false           Is synthetic?: false         Parameter class: int          Parameter name: arg1               Modifiers: 0            Is implicit?: false        Is name present?: false           Is synthetic?: false

3.getModifiers:返回一个Int值表示该形参的特征.这个值是下面这些值中被应用到该形参的值的和.


4.isImplicit: 返回true如果这个参数是被隐式的声明.

5.isNamePresent: 返回true如果该参数在.class文件中有对应的名称.

6.isSynthetic: 返回true如果这个参数既不是显示也不是隐式声明的.

(详细介绍Implicit和synthetic 请看下一小节)


隐式参数和合成参数:


有一些结构虽然没有被显示的在源码中声明,但是它却被隐式的声明了.例如 ExampleMethods类并没有包含构造函数.一个默认的构造函数被隐式的声明了.

MethodParameterSpy显示了ExampleMethods类中隐式声明的构造函数.

Number of declared constructors: 1public ExampleMethods()


考虑一下情况:

public class MethodParameterExamples {    public class InnerClass { }}

MethodParameterExamples是一个非静态的内部类. 一个默认的构造函数被隐式的为其声明.然而,然而这个构造函数还包含了一个参数.当java编译器编译内部类的时候,它会创建一个.class文件.类似于这个:

public class MethodParameterExamples {    public class InnerClass {        final MethodParameterExamples parent;        InnerClass(final MethodParameterExamples this$0) {            parent = this$0;         }    }}

内部类的构造函数使用包含该内部类的类作为参数.因此,实例MethodParameterExample显示如下:

public MethodParameterExamples$InnerClass(MethodParameterExamples)         Parameter class: class MethodParameterExamples          Parameter name: this$0               Modifiers: 32784            Is implicit?: true        Is name present?: true           Is synthetic?: false

因为InnerClass的构造函数是隐式声明的,那么他的参数也是隐式声明的.

注意:

  • java编译器为一个内部类创建一个构造函数是为了可以在创建包含该内部类的类时,方便的将该类的实例传递给该内部类.
  • 值32784说明了InerClass的构造函数同时是final(16)类型和implicit(32768)

Constructs emitted by a Java compiler are marked as synthetic if they do not correspond to a construct declared explicitly or implicitly in source code, unless they are class initialization methods. Synthetic constructs are artifacts generated by compilers that vary among different implementations. Consider the following excerpt from 

Note:

  • The Java compiler creates a formal parameter for the constructor of an inner class to enable the compiler to pass a reference (representing the immediately enclosing instance) from the creation expression to the member class's constructor.
  • The value 32784 means that the parameter of the InnerClass constructor is both final (16) and implicit (32768).
  • The Java programming language allows variable names with dollar signs ($); however, by convention, dollar signs are not used in variable names.

Constructs emitted by a Java compiler are marked as synthetic if they do not correspond to a construct declared explicitly or implicitly in source code, unless they are class initialization methods. Synthetic constructs are artifacts generated by compilers that vary among different implementations. Consider the following excerpt from MethodParameterExamples:

由java编译器生成, 并且该结构在源代码中没有被显示或者隐式的声明,并且该结构不是类初始化方法.则该结果被标记为synthetic.不同的编译器会生成不同的合成结构.

考虑以下情况 MethodParameterExamples:

public class MethodParameterExamples {    enum Colors {        RED, WHITE;    }}

当java编译器遇到一个枚举结构,它会创建一系列方法.提供枚举类型所需要的功能.例如. java编译器会为enum结构Color创建以个.class文件,该文件内容如下:

final class Colors extends java.lang.Enum<Colors> {    public final static Colors RED = new Colors("RED", 0);    public final static Colors BLUE = new Colors("WHITE", 1);     private final static values = new Colors[]{ RED, BLUE };     private Colors(String name, int ordinal) {        super(name, ordinal);    }     public static Colors[] values(){        return values;    }     public static Colors valueOf(String name){        return (Colors)java.lang.Enum.valueOf(Colors.class, name);    }}

java编译器为Color枚举结构创建了三个方法: Colors(String name, int ordinal)Colors[] values(), 和 Colors valueOf(String name). 方法values和valueOf是隐式声明的,因此它的形参也是隐式的.

枚举的构造函数Colors(String name, int ordinal) 是一个默认的构造函数,它是隐式声明的.然而,它的形参却不是隐式的.因为它的参数既不是显示也不是隐式声明的,所以它们是synthetic.(合成的). (枚举类型的默认构造函数的形参不是隐式声明,因为不同的编译器不一定会采用相同的形式.另外一个java编译器可能指定不同的形参.当编译器编译使用枚举常量的时候,依赖的是枚举结构的共有的域,这些域是隐式声明的.而不会依赖构造函数或者这些变量是怎么被初始化的)


MethodParameterExample展示了枚举类型Colors的相关信息:

enum Colors:Number of constructors: 0Number of declared constructors: 1Declared constructor #1private MethodParameterExamples$Colors()         Parameter class: class java.lang.String          Parameter name: $enum$name               Modifiers: 4096            Is implicit?: false        Is name present?: true           Is synthetic?: true         Parameter class: int          Parameter name: $enum$ordinal               Modifiers: 4096            Is implicit?: false        Is name present?: true           Is synthetic?: trueNumber of methods: 2Method #1public static MethodParameterExamples$Colors[]    MethodParameterExamples$Colors.values()             Return type: class [LMethodParameterExamples$Colors;     Generic return type: class [LMethodParameterExamples$Colors;Method #2public static MethodParameterExamples$Colors    MethodParameterExamples$Colors.valueOf(java.lang.String)             Return type: class MethodParameterExamples$Colors     Generic return type: class MethodParameterExamples$Colors         Parameter class: class java.lang.String          Parameter name: name               Modifiers: 32768            Is implicit?: true        Is name present?: true           Is synthetic?: false

更多详细信息,请参考 Java Language Specification 


3.获得和解析方法修饰符


方法的修饰符有以下几种:

  • Access modifiers: publicprotected, and private
  • Modifier restricting to one instance: static
  • Modifier prohibiting value modification: final
  • Modifier requiring override: abstract
  • Modifier preventing reentrancy: synchronized
  • Modifier indicating implementation in another programming language: native
  • Modifier forcing strict floating point behavior: strictfp
  • Annotations


实例程序MethodModifierSpy 会列出给定方法名的修饰符.同时它还展示了该方法是不是合成的,是不是可变参数的等.

import java.lang.reflect.Method;import java.lang.reflect.Modifier;import static java.lang.System.out;public class MethodModifierSpy {    private static int count;    private static synchronized void inc() { count++; }    private static synchronized int cnt() { return count; }    public static void main(String... args) {try {    Class<?> c = Class.forName(args[0]);    Method[] allMethods = c.getDeclaredMethods();    for (Method m : allMethods) {if (!m.getName().equals(args[1])) {    continue;}out.format("%s%n", m.toGenericString());out.format("  Modifiers:  %s%n",   Modifier.toString(m.getModifiers()));out.format("  [ synthetic=%-5b var_args=%-5b bridge=%-5b ]%n",   m.isSynthetic(), m.isVarArgs(), m.isBridge());inc();    }    out.format("%d matching overload%s found%n", cnt(),       (cnt() == 1 ? "" : "s"));        // production code should handle this exception more gracefully} catch (ClassNotFoundException x) {    x.printStackTrace();}    }}

MethodModifierSpy的一些实例输出:

$ java MethodModifierSpy java.lang.Object waitpublic final void java.lang.Object.wait() throws java.lang.InterruptedException  Modifiers:  public final  [ synthetic=false var_args=false bridge=false ]public final void java.lang.Object.wait(long,int)  throws java.lang.InterruptedException  Modifiers:  public final  [ synthetic=false var_args=false bridge=false ]public final native void java.lang.Object.wait(long)  throws java.lang.InterruptedException  Modifiers:  public final native  [ synthetic=false var_args=false bridge=false ]3 matching overloads found$ java MethodModifierSpy java.lang.StrictMath toRadianspublic static double java.lang.StrictMath.toRadians(double)  Modifiers:  public static strictfp  [ synthetic=false var_args=false bridge=false ]1 matching overload found$ java MethodModifierSpy MethodModifierSpy incprivate synchronized void MethodModifierSpy.inc()  Modifiers: private synchronized  [ synthetic=false var_args=false bridge=false ]1 matching overload found$ java MethodModifierSpy java.lang.Class getConstructorpublic java.lang.reflect.Constructor<T> java.lang.Class.getConstructor  (java.lang.Class<T>[]) throws java.lang.NoSuchMethodException,  java.lang.SecurityException  Modifiers: public transient  [ synthetic=false var_args=true bridge=false ]1 matching overload found$ java MethodModifierSpy java.lang.String compareTopublic int java.lang.String.compareTo(java.lang.String)  Modifiers: public  [ synthetic=false var_args=false bridge=false ]public int java.lang.String.compareTo(java.lang.Object)  Modifiers: public volatile  [ synthetic=true  var_args=false bridge=true  ]2 matching overloads found

注意到 Method.isVarArgs() 返回 true 对于 Class.getConstructor()

这些说明了该方法的声明应该看起来如下:

public Constructor<T> getConstructor(Class<?>... parameterTypes)

而不是这样

public Constructor<T> getConstructor(Class<?> [] parameterTypes)

Notice that the output for String.compareTo() contains two methods. The method declared in String.java:

注意到对于方法 String.compareTo() 包含了两个方法,该方法被声明在String.java中:

public int compareTo(String anotherString);



0 0
原创粉丝点击