在JDK 8中可通过反射获得构造函数/方法参数元数据
JDK 8較不為人所知的一項新 功能是在編譯的Java類中包含參數元數據的可選功能[JDK增強建議( JEP ) 118 ]。 此功能允許Java應用程序在運行時通過反射訪問此參數元數據信息。
Java Tutorial的Reflection API路徑包括一個名為“ 獲取方法參數的名稱”的課程,該課程討論并演示了如何在Java 8中應用此新功能。該課程包括一個示例Java類MethodParameterSpy ,可以對提供的Java類運行該類以指示特征方法和構造函數參數。 本課還強調這是一項可選功能,因為在.class文件中存儲其他參數元數據會增加這些文件的大小。 該課程還指出,在某些情況下,參數名稱包含開發人員不希望在已編譯的.class文件中使用的敏感信息。
通過將-parameters選項傳遞給javac編譯器,可以將其他參數元數據包含在用Java 8編譯的.class文件中。 當一個人鍵入javac -help時,也會顯示此-parameters選項,如下一個屏幕快照所示。
該javac的甲骨文技術說明頁面顯示此附加方法/構造函數的參數數據在運行時可以訪問:在生成的類文件“房屋構造函數和方法的形式參數名稱,這樣的方法java.lang.reflect.Executable.getParameters從Reflection API可以檢索它們。” 以下代碼片段(名為ParameterDisplayer類)對此進行了演示(重點在displayParametersMetadata(String[])方法上)。
ParameterDisplayer.java
package dustin.examples.jdk8;import static java.lang.System.out; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Parameter;/*** Uses JDK 8 Parameter class to demonstrate metadata related to the parameters* of the methods and constructors of the provided class (includes private,* protected, and public methods, but does not include methods inherited from* parent classes; those classes should be individually submitted).* * @author Dustin*/ public class ParameterDisplayer {private static void displayParametersMetadata(final String[] classesNames){for (final String className : classesNames){try{final Class clazz = Class.forName(className);// Get all class's declared methods (does not get inherited methods)final Method[] declaredMethods = clazz.getDeclaredMethods();for (final Method method : declaredMethods){writeHeader("Method " + method.toGenericString()+ " has " + method.getParameterCount() + " Parameters:");int parameterCount = 0;final Parameter[] parameters = method.getParameters();for (final Parameter parameter : parameters){out.println("\targ" + parameterCount++ + ": "+ (parameter.isNamePresent() ? parameter.getName() : "Parameter Name not provided,")+ (isParameterFinal(parameter) ? " IS " : " is NOT ")+ "final, type " + parameter.getType().getCanonicalName()+ ", and parameterized type of " + parameter.getParameterizedType()+ " and " + (parameter.isVarArgs() ? "IS " : "is NOT ")+ "variable." );}}}catch (ClassNotFoundException cnfEx){out.println("Unable to find class " + className);}}}private static void writeHeader(final String headerText){out.println("\n==========================================================");out.println("= " + headerText);out.println("==========================================================");}/*** Indicate whether provided Parameter is final.* * @param parameter Parameter to be tested for 'final' modifier.* @return {@code true} if provided Parameter is 'final'.*/private static boolean isParameterFinal(final Parameter parameter){return Modifier.isFinal(parameter.getModifiers());}public static void main(final String[] arguments){if (arguments.length < 1){out.println("You must provide the fully qualified name of at least one class.");System.exit(-1);}displayParametersMetadata(arguments);} }我最初考慮過對JDK的知名類運行此類,但是意識到這并不太有用,因為這些類不太可能是使用-parameters選項構建的。 因此,我創建了一個簡單的示例類來輔助演示。 它稱為ManyMethods然后顯示。
ManyMethods.java
package dustin.examples.jdk8;import java.util.List;/*** Class with numerous methods intended to be used in demonstrating JDK 8's new* Parameter class.* * @author Dustin*/ public class ManyMethods {public ManyMethods() {}private void addArrayOfStrings(String[] strings) {}private void addManyStrings(final String ... strings) {}private void addListOfStrings(final List<String> strings) {}@Overridepublic String toString(){return "ManyMethods";} }接下來的兩個屏幕快照演示了ManyMethods不使用-parameters選項的情況下編譯的ManyMethods實例上運行ParameterDisplayer 。 最顯著的區別是,不使用-parameters選項進行編譯時,不提供參數名稱。 同樣,如果沒有-parameters選項,則在編譯時參數是否為final也沒有可信信息。 在不使用-parameters進行編譯的情況下,無論-parameters是否為final , Parameter.getModifiers()方法均不包含final 。
ParameterDisplayer類使用Parameter.isNamePresent()以編程方式標識不存在參數名稱(當未使用-parameters選項進行編譯時)。 如果未進行檢查,則Parameter.getName()返回的參數名稱將為“ arg”加上參數編號(第一個參數為arg0,第二個參數為arg1,依此類推)。
ManyMethods類中具有參數的三個方法中的ManyMethods具有該參數的final修飾符。 僅當使用-parameters選項編譯類時,才可以通過使用Parameter.getModifiers()進行反射來正確識別這些情況。
略相關的旁注:Sun / Oracle工具文檔始終由“ windows”頁面和“ solaris”頁面組成,后者通常用于描述特定工具如何在Linux和Unix上的所有版本上工作。 我注意到Java 8文檔對此進行了更改。 該文檔仍然具有“ windows”版本,但是Unix / Linux版本現在其URL中具有“ unix”。 為了說明這一點,這里是Java SE 7和Java SE 8 javac工具頁面的URL:
- http://docs.oracle.com/javase/8/docs/technotes/tools/windows/javac.html
- http://docs.oracle.com/javase/8/docs/technotes/tools/unix/javac.html
- http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html
- http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/javac.html
回到新的(使用Java 8) 參數類,值得注意的是,存儲此附加參數元數據的已編譯.class文件有所增加。 對于上面顯示的我的ManyMethods類, .class文件從909字節擴大到961字節。
像Method一樣, 構造 方法擴展了Executable ,因此Constructor類享有與Method相同的getParameters方法。 當使用這些額外信息顯式編譯代碼時,Java 8將提供有關方法和構造函數參數的更多詳細信息。
翻譯自: https://www.javacodegeeks.com/2014/04/constructormethod-parameters-metadata-available-via-reflection-in-jdk-8.html
總結
以上是生活随笔為你收集整理的在JDK 8中可通过反射获得构造函数/方法参数元数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 万寿花的功效和作用 万寿花优点是什么
- 下一篇: iphone怎么取消锁屏