Java反射基础(三)--Methods对象的使用
Method
原文地址:http://docs.oracle.com/javase/tutorial/reflect/member/method.html
1.獲得方法類型信息
一個(gè)方法的聲明包括方法名,修飾符, 參數(shù), 和返回類型,同時(shí)還有一些方法可能拋出的異常. 類?java.lang.reflect.Method?提供了一種方式讓我們可以得到方法的這些信息.
實(shí)例程序??MethodSpy?展示了枚舉一個(gè)類中所有的方法,并返回指定方法的相關(guān)信息.
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();}} }
實(shí)例輸入及其輸出:
$ 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.SecurityExceptionReturnType: class java.lang.reflect.ConstructorGenericReturnType: java.lang.reflect.Constructor<T>ParameterType: class [Ljava.lang.Class;GenericParameterType: java.lang.Class<?>[]ExceptionType: class java.lang.NoSuchMethodExceptionGenericExceptionType: class java.lang.NoSuchMethodExceptionExceptionType: class java.lang.SecurityExceptionGenericExceptionType: class java.lang.SecurityException
它的實(shí)際定義代碼為:
public Constructor<T> getConstructor(Class<?>... parameterTypes)
第一點(diǎn)需要注意的是.這里的返回和參數(shù)類型都是泛型.?Method.getGenericReturnType()?會(huì)首先在查詢類中的屬性簽名,如果找到了,那就返回該類型.如果沒有找到,該方法會(huì)去調(diào)用?Method.getReturnType()?,它的返回值便是定義該泛型時(shí)的所使用過的值.
第二點(diǎn)需要注意的是,最后一個(gè)參數(shù),??parameterType,是一個(gè)可變數(shù)量的參數(shù). 它被標(biāo)識(shí)為一個(gè)一維數(shù)組.如果要區(qū)別這個(gè)和一個(gè)顯示聲明為數(shù)組的參數(shù)的話,可以使用方法?Method.isVarArgs().
接下來的示例展示了一個(gè)返回值為泛型的例子:
$ java MethodSpy java.lang.Class cast public T java.lang.Class.cast(java.lang.Object)ReturnType: class java.lang.ObjectGenericReturnType: TParameterType: class java.lang.ObjectGenericParameterType: class java.lang.Object對(duì)于返回值是泛型的?Class.cast()?的方法,使用反射之后得到它的返回值是java.lang.Object. 這是因?yàn)樵诰幾g時(shí)期所有的跟泛型有關(guān)的信息都會(huì)被擦除. T的擦除被定義為CLass:
public final class Class<T> implements ..
最后一個(gè)示例程序展示了一個(gè)輸出一個(gè)多次重載的方法的例子:
$ 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.PrintStreamGenericReturnType: class java.io.PrintStreamParameterType: class java.util.LocaleGenericParameterType: class java.util.LocaleParameterType: class java.lang.StringGenericParameterType: class java.lang.StringParameterType: 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.PrintStreamGenericReturnType: class java.io.PrintStreamParameterType: class java.lang.StringGenericParameterType: class java.lang.StringParameterType: class [Ljava.lang.Object;GenericParameterType: class [Ljava.lang.Object;
2.獲得方法的參數(shù)名稱
我們可以通過?java.lang.reflect.Executable.getParameters.方法獲得任何方法和構(gòu)造函數(shù)的形式參數(shù)的名稱.(Method類和Constructor類都繼承Executable類,因此他們都繼承了方法Executable.getParameters.) 然而,默認(rèn)情況下.class文件并不會(huì)存儲(chǔ)形式參數(shù)名稱.
如果想要保留形參形成,我們需要編譯源碼使用-parameters 選項(xiàng).
實(shí)例程序?MethodParameterSpy?展示了如果獲取一個(gè)指定類的所有方法和構(gòu)造函數(shù)的形式參數(shù)的名稱.實(shí)例同時(shí)還展示出一些關(guān)于參數(shù)的其他信息.
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的方法和構(gòu)造函數(shù)的形參名稱.(注意:記得使用-parameters選項(xiàng)編譯ExmapleMethods)
Number of constructors: 1Constructor #1 public ExampleMethods()Number of declared constructors: 1Declared constructor #1 public ExampleMethods()Number of methods: 4Method #1 public boolean ExampleMethods.simpleMethod(java.lang.String,int)Return type: booleanGeneric return type: booleanParameter class: class java.lang.StringParameter name: stringParamModifiers: 0Is implicit?: falseIs name present?: trueIs synthetic?: falseParameter class: intParameter name: intParamModifiers: 0Is implicit?: falseIs name present?: trueIs synthetic?: falseMethod #2 public int ExampleMethods.varArgsMethod(java.lang.String...)Return type: intGeneric return type: intParameter class: class [Ljava.lang.String;Parameter name: manyStringsModifiers: 0Is implicit?: falseIs name present?: trueIs synthetic?: falseMethod #3 public boolean ExampleMethods.methodWithList(java.util.List<java.lang.String>)Return type: booleanGeneric return type: booleanParameter class: interface java.util.ListParameter name: listParamModifiers: 0Is implicit?: falseIs name present?: trueIs synthetic?: falseMethod #4 public <T> void ExampleMethods.genericMethod(T[],java.util.Collection<T>)Return type: voidGeneric return type: voidParameter class: class [Ljava.lang.Object;Parameter name: aModifiers: 0Is implicit?: falseIs name present?: trueIs synthetic?: falseParameter class: interface java.util.CollectionParameter name: cModifiers: 0Is implicit?: falseIs name present?: trueIs synthetic?: false
1.getType: 返回該參數(shù)被聲明時(shí)的類型所對(duì)應(yīng)的Class對(duì)象.
2.getName: 返回該參數(shù)的名稱.如果這個(gè)參數(shù)的名稱在.class文件中可以找到,那么就返回該名稱.如果沒有找到,
那么會(huì)自動(dòng)生成一個(gè)名稱,argN.其 中N是參數(shù)的索引.
作為一個(gè)示例,不適用-parameters選項(xiàng)編譯ExampleMethods源碼.那么MethodParameterSpy將會(huì)打印出如下信息:
public boolean ExampleMethods.simpleMethod(java.lang.String,int)Return type: booleanGeneric return type: booleanParameter class: class java.lang.StringParameter name: arg0Modifiers: 0Is implicit?: falseIs name present?: falseIs synthetic?: falseParameter class: intParameter name: arg1Modifiers: 0Is implicit?: falseIs name present?: falseIs synthetic?: false
3. getModifiers:返回一個(gè)Int值表示該形參的特征.這個(gè)值是下面這些值中被應(yīng)用到該形參的值的和.
4.isImplicit: 返回true如果這個(gè)參數(shù)是被隱式的聲明.
5.isNamePresent: 返回true如果該參數(shù)在.class文件中有對(duì)應(yīng)的名稱.
6.isSynthetic: 返回true如果這個(gè)參數(shù)既不是顯示也不是隱式聲明的.
(詳細(xì)介紹Implicit和synthetic 請(qǐng)看下一小節(jié))
隱式參數(shù)和合成參數(shù):
有一些結(jié)構(gòu)雖然沒有被顯示的在源碼中聲明,但是它卻被隱式的聲明了.例如 ExampleMethods類并沒有包含構(gòu)造函數(shù).一個(gè)默認(rèn)的構(gòu)造函數(shù)被隱式的聲明了.
MethodParameterSpy顯示了ExampleMethods類中隱式聲明的構(gòu)造函數(shù).
Number of declared constructors: 1 public ExampleMethods()
考慮一下情況:
public class MethodParameterExamples {public class InnerClass { } }MethodParameterExamples是一個(gè)非靜態(tài)的內(nèi)部類. 一個(gè)默認(rèn)的構(gòu)造函數(shù)被隱式的為其聲明.然而,然而這個(gè)構(gòu)造函數(shù)還包含了一個(gè)參數(shù).當(dāng)java編譯器編譯內(nèi)部類的時(shí)候,它會(huì)創(chuàng)建一個(gè).class文件.類似于這個(gè):
public class MethodParameterExamples {public class InnerClass {final MethodParameterExamples parent;InnerClass(final MethodParameterExamples this$0) {parent = this$0; }} }內(nèi)部類的構(gòu)造函數(shù)使用包含該內(nèi)部類的類作為參數(shù).因此,實(shí)例MethodParameterExample顯示如下:
public MethodParameterExamples$InnerClass(MethodParameterExamples)Parameter class: class MethodParameterExamplesParameter name: this$0Modifiers: 32784Is implicit?: trueIs name present?: trueIs synthetic?: false因?yàn)镮nnerClass的構(gòu)造函數(shù)是隱式聲明的,那么他的參數(shù)也是隱式聲明的.
注意:
- java編譯器為一個(gè)內(nèi)部類創(chuàng)建一個(gè)構(gòu)造函數(shù)是為了可以在創(chuàng)建包含該內(nèi)部類的類時(shí),方便的將該類的實(shí)例傳遞給該內(nèi)部類.
- 值32784說明了InerClass的構(gòu)造函數(shù)同時(shí)是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編譯器生成, 并且該結(jié)構(gòu)在源代碼中沒有被顯示或者隱式的聲明,并且該結(jié)構(gòu)不是類初始化方法.則該結(jié)果被標(biāo)記為synthetic.不同的編譯器會(huì)生成不同的合成結(jié)構(gòu).考慮以下情況?MethodParameterExamples:
public class MethodParameterExamples {enum Colors {RED, WHITE;} }
當(dāng)java編譯器遇到一個(gè)枚舉結(jié)構(gòu),它會(huì)創(chuàng)建一系列方法.提供枚舉類型所需要的功能.例如. java編譯器會(huì)為enum結(jié)構(gòu)Color創(chuàng)建以個(gè).class文件,該文件內(nèi)容如下:
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枚舉結(jié)構(gòu)創(chuàng)建了三個(gè)方法:?Colors(String name, int ordinal),?Colors[] values(), 和?Colors valueOf(String name). 方法values和valueOf是隱式聲明的,因此它的形參也是隱式的.
枚舉的構(gòu)造函數(shù) Colors(String name, int ordinal) ?是一個(gè)默認(rèn)的構(gòu)造函數(shù),它是隱式聲明的.然而,它的形參卻不是隱式的.因?yàn)樗膮?shù)既不是顯示也不是隱式聲明的,所以它們是synthetic.(合成的).?( 枚舉類型的默認(rèn)構(gòu)造函數(shù)的形參不是隱式聲明,因?yàn)椴煌木幾g器不一定會(huì)采用相同的形式.另外一個(gè)java編譯器可能指定不同的形參.當(dāng)編譯器編譯使用枚舉常量的時(shí)候,依賴的是枚舉結(jié)構(gòu)的共有的域,這些域是隱式聲明的.而不會(huì)依賴構(gòu)造函數(shù)或者這些變量是怎么被初始化的)
MethodParameterExample展示了枚舉類型Colors的相關(guān)信息:
enum Colors:Number of constructors: 0Number of declared constructors: 1Declared constructor #1 private MethodParameterExamples$Colors()Parameter class: class java.lang.StringParameter name: $enum$nameModifiers: 4096Is implicit?: falseIs name present?: trueIs synthetic?: trueParameter class: intParameter name: $enum$ordinalModifiers: 4096Is implicit?: falseIs name present?: trueIs synthetic?: trueNumber of methods: 2Method #1 public static MethodParameterExamples$Colors[]MethodParameterExamples$Colors.values()Return type: class [LMethodParameterExamples$Colors;Generic return type: class [LMethodParameterExamples$Colors;Method #2 public static MethodParameterExamples$ColorsMethodParameterExamples$Colors.valueOf(java.lang.String)Return type: class MethodParameterExamples$ColorsGeneric return type: class MethodParameterExamples$ColorsParameter class: class java.lang.StringParameter name: nameModifiers: 32768Is implicit?: trueIs name present?: trueIs synthetic?: false
更多詳細(xì)信息,請(qǐng)參考?Java Language Specification?
3.獲得和解析方法修飾符
方法的修飾符有以下幾種:
- Access modifiers:?public,?protected, 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
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的一些實(shí)例輸出:
$ java MethodModifierSpy java.lang.Object wait public final void java.lang.Object.wait() throws java.lang.InterruptedExceptionModifiers: public final[ synthetic=false var_args=false bridge=false ] public final void java.lang.Object.wait(long,int)throws java.lang.InterruptedExceptionModifiers: public final[ synthetic=false var_args=false bridge=false ] public final native void java.lang.Object.wait(long)throws java.lang.InterruptedExceptionModifiers: 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.SecurityExceptionModifiers: 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?對(duì)于?Class.getConstructor().?
這些說明了該方法的聲明應(yīng)該看起來如下:
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 :
注意到對(duì)于方法?String.compareTo()?包含了兩個(gè)方法,該方法被聲明在String.java中:
public int compareTo(String anotherString);
總結(jié)
以上是生活随笔為你收集整理的Java反射基础(三)--Methods对象的使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用DC
- 下一篇: Golang 词法分析器浅析