Java 中文官方教程 2022 版(四十三)(4)

简介: Java 中文官方教程 2022 版(四十三)

Java 中文官方教程 2022 版(四十三)(3)https://developer.aliyun.com/article/1488268

获取方法参数的名称

原文:docs.oracle.com/javase/tutorial/reflect/member/methodparameterreflection.html

您可以使用方法java.lang.reflect.Executable.getParameters获取任何方法或构造函数的形式参数的名称。(类MethodConstructor扩展了类Executable,因此继承了方法Executable.getParameters。)但是,默认情况下,.class文件不会存储形式参数名称。这是因为许多生成和消费类文件的工具可能不希望.class文件包含参数名称的更大的静态和动态占用空间。特别是,这些工具将不得不处理更大的.class文件,并且 Java 虚拟机(JVM)将使用更多内存。此外,一些参数名称,如secretpassword,可能会暴露有关安全敏感方法的信息。

要在特定的.class文件中存储形式参数名称,并使反射 API 能够检索形式参数名称,请使用javac编译器的-parameters选项编译源文件。

MethodParameterSpy示例演示了如何检索给定类的所有构造函数和方法的形式参数的名称。该示例还打印有关每个参数的其他信息。

以下命令打印类ExampleMethods的构造函数和方法的形式参数名称。注意:记得使用-parameters编译器选项编译示例ExampleMethods

*java MethodParameterSpy ExampleMethods*

此命令打印以下内容:

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

MethodParameterSpy示例使用Parameter类中的以下方法:

  • getType: 返回标识参数声明类型的Class对象。
  • getName: 返回参数的名称。如果参数的名称存在,则此方法返回.class文件提供的名称。否则,此方法将合成一个形式为arg*N*的名称,其中*N*是声明参数的方法描述符中的参数索引。
    例如,假设您编译了类ExampleMethods而没有指定-parameters编译器选项。示例MethodParameterSpy将为方法ExampleMethods.simpleMethod打印以下内容:
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
  • getModifiers:返回一个整数,表示形式参数具有的各种特征。如果适用于形式参数,则此值是以下值的总和:
值(十进制) 值(十六进制) 描述
16 0x0010 形式参数声明为final
4096 0x1000 形式参数是合成的。或者,您可以调用方法isSynthetic
32768 0x8000 参数在源代码中是隐式声明的。或者,您可以调用方法isImplicit

  • isImplicit:如果此参数在源代码中是隐式声明的,则返回true。有关更多信息,请参阅隐式和合成参数部分。
  • isNamePresent:如果参数在.class文件中具有名称,则返回true
  • isSynthetic:如果此参数在源代码中既不是隐式声明也不是显式声明,则返回true。有关更多信息,请参阅隐式和合成参数部分。

隐式和合成参数

如果源代码中未明确编写某些构造,则某些构造将被隐式声明。例如,ExampleMethods示例不包含构造函数。它将隐式声明一个默认构造函数。MethodParameterSpy示例打印有关ExampleMethods隐式声明构造函数的信息:

Number of declared constructors: 1
public ExampleMethods()

请考虑来自MethodParameterExamples的以下摘录:

public class MethodParameterExamples {
    public class InnerClass { }
}

InnerClass是一个非静态嵌套类或内部类。内部类也会隐式声明一个构造函数。但是,此构造函数将包含一个参数。当 Java 编译器编译InnerClass时,它会创建一个代表以下代码的.class文件:

public class MethodParameterExamples {
    public class InnerClass {
        final MethodParameterExamples parent;
        InnerClass(final MethodParameterExamples this$0) {
            parent = this$0; 
        }
    }
}

InnerClass构造函数包含一个参数,其类型是包含InnerClass的类,即MethodParameterExamples。因此,示例MethodParameterExamples打印如下内容:

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 表示InnerClass构造函数的参数既是 final(16)又是隐式的(32768)。
  • Java 编程语言允许在变量名中使用美元符号($);然而,按照惯例,在变量名中不使用美元符号。

Java 编译器生成的构造如果不对应于源代码中显式或隐式声明的构造,则标记为合成的,除非它们是类初始化方法。合成的构造是编译器生成的在不同实现之间变化的工件。考虑以下摘录来自MethodParameterExamples

public class MethodParameterExamples {
    enum Colors {
        RED, WHITE;
    }
}

当 Java 编译器遇到enum构造时,它会创建几个与.class文件结构兼容且提供enum构造所期望功能的方法。例如,Java 编译器会为代表以下代码的enum构造Colors创建一个.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 编译器为这个enum构造创建了三个构造函数和方法:Colors(String name, int ordinal)Colors[] values()Colors valueOf(String name)。方法valuesvalueOf是隐式声明的。因此,它们的形式参数名称也是隐式声明的。

enum构造函数Colors(String name, int ordinal)是一个默认构造函数,它是隐式声明的。然而,这个构造函数的形式参数(nameordinal并没有隐式声明。因为这些形式参数既没有显式声明也没有隐式声明,它们是合成的。(enum构造函数的默认构造函数的形式参数不是隐式声明的,因为不同的编译器可能对这个构造函数的形式参数形式有不同的规定;另一个 Java 编译器可能为其指定不同的形式参数。当编译器编译使用enum常量的表达式时,它们仅依赖于enum构造的公共静态字段,这些字段是隐式声明的,而不依赖于它们的构造函数或这些常量是如何初始化的。)

因此,示例MethodParameterExample关于enum构造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 语言规范,包括在反射 API 中出现为隐式的参数。

检索和解析方法修饰符

原文:docs.oracle.com/javase/tutorial/reflect/member/methodModifiers.html

方法声明中可能包含的几个修饰符:

  • 访问修饰符:publicprotectedprivate
  • 限制为一个实例的修饰符:static
  • 禁止值修改的修饰符:final
  • 要求覆盖的修饰符:abstract
  • 防止重入的修饰符:synchronized
  • 表示在另一种编程语言中实现的修饰符:native
  • 强制严格浮点行为的修饰符:strictfp
  • 注解

MethodModifierSpy示例列出了具有给定名称的方法的修饰符。它还显示方法是否是合成的(编译器生成的)、可变参数的,或者是桥接方法(编译器生成的以支持泛型接口)。

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()对于Class.getConstructor()返回true。这表明方法声明如下:

public Constructor<T> getConstructor(Class<?>... parameterTypes)

不要这样:

public Constructor<T> getConstructor(Class<?> [] parameterTypes)

请注意,String.compareTo()的输出包含两种方法。在String.java中声明的方法:

public int compareTo(String anotherString);

和第二个合成或编译器生成的桥接方法。这是因为String实现了参数化接口Comparable。在类型擦除期间,继承方法Comparable.compareTo()的参数类型从java.lang.Object更改为java.lang.String。由于ComparableString中的compareTo方法的参数类型在擦除后不再匹配,因此无法进行覆盖。在所有其他情况下,这将产生编译时错误,因为接口未实现。桥接方法的添加避免了这个问题。

Method实现了java.lang.reflect.AnnotatedElement。因此,任何具有java.lang.annotation.RetentionPolicy.RUNTIME的运行时注解都可以被检索。有关获取注解的示例,请参见检查类修饰符和类型部分。

相关文章
|
1天前
|
Java 数据库连接 数据处理
探究Java异常处理【保姆级教程】
Java 异常处理是确保程序稳健运行的关键机制。它通过捕获和处理运行时错误,避免程序崩溃。Java 的异常体系以 `Throwable` 为基础,分为 `Error` 和 `Exception`。前者表示严重错误,后者可细分为受检和非受检异常。常见的异常处理方式包括 `try-catch-finally`、`throws` 和 `throw` 关键字。此外,还可以自定义异常类以满足特定需求。最佳实践包括捕获具体异常、合理使用 `finally` 块和谨慎抛出异常。掌握这些技巧能显著提升程序的健壮性和可靠性。
15 4
|
1天前
|
存储 移动开发 算法
【潜意识Java】Java基础教程:从零开始的学习之旅
本文介绍了 Java 编程语言的基础知识,涵盖从简介、程序结构到面向对象编程的核心概念。首先,Java 是一种高级、跨平台的面向对象语言,支持“一次编写,到处运行”。接着,文章详细讲解了 Java 程序的基本结构,包括包声明、导入语句、类声明和 main 方法。随后,深入探讨了基础语法,如数据类型、变量、控制结构、方法和数组。此外,还介绍了面向对象编程的关键概念,例如类与对象、继承和多态。最后,针对常见的编程错误提供了调试技巧,并总结了学习 Java 的重要性和方法。适合初学者逐步掌握 Java 编程。
10 1
|
27天前
|
移动开发 前端开发 Java
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
JavaFX是Java的下一代图形用户界面工具包。JavaFX是一组图形和媒体API,我们可以用它们来创建和部署富客户端应用程序。 JavaFX允许开发人员快速构建丰富的跨平台应用程序,允许开发人员在单个编程接口中组合图形,动画和UI控件。本文详细介绍了JavaFx的常见用法,相信读完本教程你一定有所收获!
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
|
1月前
|
NoSQL Java 关系型数据库
Liunx部署java项目Tomcat、Redis、Mysql教程
本文详细介绍了如何在 Linux 服务器上安装和配置 Tomcat、MySQL 和 Redis,并部署 Java 项目。通过这些步骤,您可以搭建一个高效稳定的 Java 应用运行环境。希望本文能为您在实际操作中提供有价值的参考。
148 26
|
1天前
|
前端开发 Java 开发工具
Git使用教程-将idea本地Java等文件配置到gitte上【保姆级教程】
本内容详细介绍了使用Git进行版本控制的全过程,涵盖从本地仓库创建到远程仓库配置,以及最终推送代码至远程仓库的步骤。
11 0
|
1月前
|
安全 Java 编译器
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
|
1月前
|
Java 开发工具 Android开发
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
Kotlin教程笔记(26) -Kotlin 与 Java 共存(一)
|
2月前
|
Java 编译器 Android开发
Kotlin教程笔记(28) -Kotlin 与 Java 混编
Kotlin教程笔记(28) -Kotlin 与 Java 混编
42 2
|
1月前
|
Java 数据库连接 编译器
Kotlin教程笔记(29) -Kotlin 兼容 Java 遇到的最大的“坑”
Kotlin教程笔记(29) -Kotlin 兼容 Java 遇到的最大的“坑”
66 0
|
2月前
|
安全 Java 编译器
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)
Kotlin教程笔记(27) -Kotlin 与 Java 共存(二)