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 getConstructor
public 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 cast
public 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 format
public 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: 1
Constructor #1
public ExampleMethods()
Number of declared constructors: 1
Declared constructor #1
public ExampleMethods()
Number of methods: 4
Method #1
public 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?: false
Method #2
public 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?: false
Method #3
public 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?: false
Method #4
public <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: 1
public 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: 0
Number of declared constructors: 1
Declared constructor #1
private 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?: true
Number of methods: 2
Method #1
public static MethodParameterExamples$Colors[]
MethodParameterExamples$Colors.values()
Return type: class [LMethodParameterExamples$Colors;
Generic return type: class [LMethodParameterExamples$Colors;
Method #2
public 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 wait
public 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 toRadians
public 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 inc
private synchronized void MethodModifierSpy.inc()
Modifiers: private synchronized
[ synthetic=false var_args=false bridge=false ]
1 matching overload found
$ java MethodModifierSpy java.lang.Class getConstructor
public 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 compareTo
public 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);