Java反射类 java.lang.reflect.Constructor构造函数类介绍

x33g5p2x  于2021-08-20 转载在 Java  
字(7.5k)|赞(0)|评价(0)|浏览(540)

1. 概述

构造函数用于创建一个作为类的实例的对象。通常,在方法被调用或字段被访问之前,它执行初始化类所需的操作。构造函数是不被继承的。

在处理构造函数时使用的关键类是Class和java.lang.reflect.Constructor。本帖的源代码可在GitHub上找到。
下面的类图显示了java.lang.reflect.Constructor提供的反射API的列表。

Java 构造函数的反射

2. 反射构造函数API示例

  • 寻找构造函数
  • 检索和解析构造函数修饰符
  • 创建新的类实例
  • 获取构造函数
  • 获取构造函数信息

2.1 寻找构造函数

构造函数声明包括名称、修改器、参数和可抛出的异常列表。java.lang.reflect.Constructor类提供了一种获取这些信息的方法。

ConstructorSift 示例说明了如何在一个类的声明构造函数中搜索一个有指定类型参数的构造函数。

package com.javaguides.reflection.constructors;

import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import static java.lang.System.out;
 
public class ConstructorSift {
    public static void main(String... args) {
    try {
        Class<?> cArg = Class.forName("java.util.Locale");
 
        Class<?> c = Class.forName("java.util.Formatter");
        Constructor[] allConstructors = c.getDeclaredConstructors();
        for (Constructor ctor : allConstructors) {
        Class<?>[] pType  = ctor.getParameterTypes();
        for (int i = 0; i < pType.length; i++) {
            if (pType[i].equals(cArg)) {
            out.format("%s%n", ctor.toGenericString());
 
            Type[] gpType = ctor.getGenericParameterTypes();
            for (int j = 0; j < gpType.length; j++) {
                char ch = (pType[j].equals(cArg) ? '/*' : ' ');
                out.format("%7c%s[%d]: %s%n", ch,
                       "GenericParameterType", j, gpType[j]);
            }
            break;
            }
        }
        }
 
        // production code should handle this exception more gracefully
    } catch (ClassNotFoundException x) {
        x.printStackTrace();
    }
    }
}

输出。

public java.util.Formatter(java.lang.String,java.lang.String,java.util.Locale) 
throws java.io.FileNotFoundException,java.io.UnsupportedEncodingException
       GenericParameterType[0]: class java.lang.String
       GenericParameterType[1]: class java.lang.String
      *GenericParameterType[2]: class java.util.Locale
public java.util.Formatter(java.io.File,java.lang.String,java.util.Locale) 
throws java.io.FileNotFoundException,java.io.UnsupportedEncodingException
       GenericParameterType[0]: class java.io.File
       GenericParameterType[1]: class java.lang.String
      *GenericParameterType[2]: class java.util.Locale
private java.util.Formatter(java.nio.charset.Charset,java.util.Locale,java.io.File) 
throws java.io.FileNotFoundException
       GenericParameterType[0]: class java.nio.charset.Charset
      *GenericParameterType[1]: class java.util.Locale
       GenericParameterType[2]: class java.io.File
private java.util.Formatter(java.util.Locale,java.lang.Appendable)
      *GenericParameterType[0]: class java.util.Locale
       GenericParameterType[1]: interface java.lang.Appendable
public java.util.Formatter(java.io.OutputStream,java.lang.String,java.util.Locale) 
throws java.io.UnsupportedEncodingException
       GenericParameterType[0]: class java.io.OutputStream
       GenericParameterType[1]: class java.lang.String
      *GenericParameterType[2]: class java.util.Locale
public java.util.Formatter(java.lang.Appendable,java.util.Locale)
       GenericParameterType[0]: interface java.lang.Appendable
      *GenericParameterType[1]: class java.util.Locale
public java.util.Formatter(java.util.Locale)
      *GenericParameterType[0]: class java.util.Locale

2.2 检索和解析构造函数修改器

由于构造函数在语言中的作用,有意义的修饰符比方法少。

  • 访问修饰符:public, protected, 和 private
  • 注释
    ConstructorAccess例子在一个给定的类中搜索具有指定访问修饰符的构造函数。它还显示构造函数是合成的(编译器生成的)还是可变节数的。
package com.javaguides.reflection.constructors;

import static java.lang.System.out;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

public class ConstructorAccess {
 public static void main(String... args) {
  try {
      Class<?> c = Class.forName("java.io.File");
      Constructor[] allConstructors = c.getDeclaredConstructors();
      for (Constructor ctor : allConstructors) {
          int searchMod = modifierFromString("private");
          int mods = accessModifiers(ctor.getModifiers());
          if (searchMod == mods) {
             out.format("%s%n", ctor.toGenericString());
             out.format("  [ synthetic=%-5b var_args=%-5b ]%n", ctor.isSynthetic(), ctor.isVarArgs());
          }
      }

     // production code should handle this exception more gracefully
  } catch (ClassNotFoundException x) {
      x.printStackTrace();
  }
 }

 private static int accessModifiers(int m) {
     return m & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED);
 }

 private static int modifierFromString(String s) {
     if ("public".equals(s))
         return Modifier.PUBLIC;
     else if ("protected".equals(s))
         return Modifier.PROTECTED;
     else if ("private".equals(s))
         return Modifier.PRIVATE;
     else if ("package-private".equals(s))
         return 0;
     else
         return -1;
 }
}

输出:

private java.io.File(java.lang.String,java.io.File)
  [ synthetic=false var_args=false ]
private java.io.File(java.lang.String,int)
  [ synthetic=false var_args=false ]

2.3 创建新的类实例

有两种创建类实例的反射方法:java.lang.reflect.Constructor.newInstance() 和 Class.newInstance()。

package com.javaguides.reflection.constructors;

import java.io.Console;
import java.nio.charset.Charset;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import static java.lang.System.out;

public class ConsoleCharset {
 public static void main(String... args) {
     Constructor[] ctors = Console.class.getDeclaredConstructors();
     Constructor ctor = null;
     for (int i = 0; i < ctors.length; i++) {
        ctor = ctors[i];
         if (ctor.getGenericParameterTypes().length == 0)
          break;
     }

     try {
        ctor.setAccessible(true);
        Console c = (Console) ctor.newInstance();
        Field f = c.getClass().getDeclaredField("cs");
        f.setAccessible(true);
        out.format("Console charset         :  %s%n", f.get(c));
        out.format("Charset.defaultCharset():  %s%n", Charset.defaultCharset());

        // production code should handle these exceptions more gracefully
        } catch (InstantiationException x) {
            x.printStackTrace();
        } catch (InvocationTargetException x) {
            x.printStackTrace();
        } catch (IllegalAccessException x) {
            x.printStackTrace();
        } catch (NoSuchFieldException x) {
            x.printStackTrace();
        }
    }
}

输出:

Console charset         :  windows-1252
Charset.defaultCharset():  windows-1252

让我们再来学习几个例子,首先创建Customer.java类并在Customerclass上应用反射构造器API。

###Customer.java

package com.javaguides.reflection.constructors;

public class Customer {
    private int id;
    private String firstName;
    private String lastName;
    public Customer(int id, String firstName, String lastName) {
        super();
        this.id = id;
        this.firstName = firstName;
        this.lastName = lastName;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getFirstName() {
       return firstName;
    }
    public void setFirstName(String firstName) {
       this.firstName = firstName;
    }
    public String getLastName() {
       return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}

2.4 获取构造函数

在一个对象的类表示中使用getConstructor()_方法来获取特定的公共构造函数。

Class<?> clazz = Class.forName("com.javaguides.reflection.constructors.Customer");

Constructor<?> constructor = clazz.getConstructor(int.class, String.class, String.class);

// getting constructor parameters
System.out.println(Arrays.toString(constructor.getParameterTypes()));

Constructor<?> hashMapConstructor = Class.forName("java.util.HashMap").getConstructor(null);

System.out.println(Arrays.toString(hashMapConstructor.getParameterTypes()));

输出:

[int, class java.lang.String, class java.lang.String]
[]

2.5 获取构造函数信息

让我们使用构造函数反射API来获取客户构造函数信息。

Class<?> clazz = Class.forName("com.javaguides.reflection.constructors.Customer");
Constructor[] constructors = clazz.getConstructors();
for (Constructor<?> constructor : constructors) {

      // get constructor name
      System.out.println(constructor.getName());

      // get constructor parameters
      System.out.println(Arrays.toString(constructor.getParameterTypes()));

      // Get parameter count
      System.out.println(constructor.getParameterCount());

     System.out.println(constructor.getDeclaringClass().getCanonicalName());
   }

输出:

com.javaguides.reflection.constructors.Customer
[int, class java.lang.String, class java.lang.String]
3
com.javaguides.reflection.constructors.Customer

3. 参考资料

https://docs.oracle.com/javase/tutorial/reflect/class/index.html

https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/package-summary.html
https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Constructor.html

相关文章