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 ..
最后一个示例程序展示了一个输出一个多次重载的方法的例子:
$ 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
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
:
考虑以下情况 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:
public
,protected
, andprivate
- 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
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);
- Java反射基础(三)--Methods对象的使用
- Java反射基础(二)--Fileds对象的使用
- java基础-反射2(反射,反射操作对象,Class对象的使用,类型信息的获取)
- Java反射的基础使用
- java 反射之获取class对象的三种方式
- java反射之获取class对象的三种方式
- java反射(2)获取Class对象的三种方法
- Java基础之反射的三种实现方式
- java反射的基础
- JAVA反射的基础
- JAVA 的反射基础
- Java的反射基础
- 使用java 反射 copy 对象
- java使用反射创建对象
- 【框架基础】:Java反射机制详解(三)
- 【框架基础】:Java反射机制详解(三)
- Java反射基础(一)--Class对象获取
- JAVA基础 (三)反射 深入解析反射机制
- Convert Sorted List to Binary Search Tree
- Permutation 题解
- CSS JS 添加版本号
- OPENSSL https 证书的使用Demo(证书加密码)
- 数值概率算法
- Java反射基础(三)--Methods对象的使用
- 《C++并发编程实战》读书笔记3---线程同步
- android中如何获取视频文件的第一祯并显示在imageview上
- 概率算法
- POJ2034 Anti-prime Sequences【素数筛法】【DFS】
- 音效播放小demo
- Android 如何在自定义界面上启用输入法 (How to enable inputmethod for the custom UI)
- 位运算
- Unity中贴图的导入