jdk1.8 ::构造函数
JDK 8较不广为人知的新 功能之一是在已编译的Java类中包含参数元数据的可选功能[JDK增强建议( JEP ) 118 ]。 此功能允许Java应用程序在运行时通过反射访问此参数元数据信息。
Java教程的Reflection API路径包括一个名为“ 获取方法参数的名称”的课程,该课程讨论并演示了如何在Java 8中应用此新功能。该课程包括一个示例Java类MethodParameterSpy ,可以对提供的Java类运行该类以指示特征方法和构造函数参数。 本课还强调这是一项可选功能,因为在.class
文件中存储其他参数元数据会增加这些文件的大小。 该课程还指出,在某些情况下,参数名称包含开发人员不希望在已编译的.class
文件中使用的敏感信息。
通过将-parameters
选项传递给javac编译器,可以将其他参数元数据包含在用Java 8编译的.class
文件中。 当一个人键入javac -help
时,也会显示此-parameters
选项,如下一个屏幕快照所示。
javac上的Oracle TechNotes页面指示如何在运行时访问此附加的方法/构造函数参数数据:“将构造函数和方法的形式参数名称存储在生成的类文件中,以便从中获取方法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";}
}
接下来的两个屏幕快照演示了在不使用-parameters
选项和使用-parameters
选项编译的ManyMethods
实例上运行ParameterDisplayer
的ManyMethods
。 最显着的区别是,不使用-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
jdk1.8 ::构造函数