02. Java如何通过反射访问构造方法?
为了能够动态获取对象构造方法的信息,首先需要创建一个Constructor类型的对象或者数组:
- getConstructors()
- getConstructor(Class<?>…parameterTypes)
- getDeclaredConstructors()
- getDeclaredConstructor(Class<?>…parameterTypes)
如果是访问指定的构造方法,需要根据该构造方法的入口参数类型来访问。例如,访问一个入口参数一次为int、string类型的构造方法,下面的两种方式均可实现:
1 2
| objectClass.getDeclaredConstructor(int.class,String.class); objectClass.getDeclaredConstructor(new Class[]{int.class,String.class});
|
创建的每个Constructor对象表示一个构造方法,然后利用Constructor对象的方法操作构造方法。Constructor类的常用方法:
方法名称 |
说明 |
isVarArgs() |
查看该构造方法是否允许带可变数量的参数,如果允许,返回 true,否则返回 false |
getParameterTypes() |
按照声明顺序以 Class 数组的形式获取该构造方法各个参数的类型 |
getExceptionTypes() |
以 Class 数组的形式获取该构造方法可能抛出的异常类型 |
newInstance(Object … initargs) |
通过该构造方法利用指定参数创建一个该类型的对象,如果未设置参数则表示 采用默认无参的构造方法 |
setAccessiable(boolean flag) |
如果该构造方法的权限为 private,默认为不允许通过反射利用 netlnstance() 方法创建对象。如果先执行该方法,并将入口参数设置为 true,则允许创建对 象 |
getModifiers() |
获得可以解析出该构造方法所采用修饰符的整数 |
通过 java.lang.reflect.Modifier 类可以解析出 getMocMers() 方法的返回值所表示的修饰符信息。在该类中提供了一系列用来解析的静态方法,既可以查看是否被指定的修饰符修饰,还可以字符串的形式获得所有修饰符。以下为 Modifier 类的常用静态方法:
静态方法名称 |
说明 |
isStatic(int mod) |
如果使用 static 修饰符修饰则返回 true,否则返回 false |
isPublic(int mod) |
如果使用 public 修饰符修饰则返回 true,否则返回 false |
isProtected(int mod) |
如果使用 protected 修饰符修饰则返回 true,否则返回 false |
isPrivate(int mod) |
如果使用 private 修饰符修饰则返回 true,否则返回 false |
isFinal(int mod) |
如果使用 final 修饰符修饰则返回 true,否则返回 false |
toString(int mod) |
以字符串形式返回所有修饰符 |
案例
假设类Book中,有三个构造函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class Book { String name; int id, price; private Book() { } protected Book(String _name, int _id) { this.name = _name; this.id = _id; } public Book(String... strings) throws NumberFormatException { if (0 < strings.length) id = Integer.valueOf(strings[0]); if (1 < strings.length) price = Integer.valueOf(strings[1]); } public void print() { System.out.println("name=" + name); System.out.println("id=" + id); System.out.println("price=" + price); } }
|
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| package com.example.basejava.reflect;
import java.lang.reflect.Constructor;
public class Test01 { public static void main(String[] args) { Class<Book> bookClass = Book.class; Constructor<?>[] declaredConstructors = bookClass.getDeclaredConstructors(); for (int i = 0; i < declaredConstructors.length; i++) { Constructor<?> con = declaredConstructors[i]; System.out.println("查看是否允许带可变数量的参数:" + con.isVarArgs()); System.out.println("该构造方法的入口参数类型依次为:"); Class<?>[] parameterTypes = con.getParameterTypes(); for (Class<?> parameterType : parameterTypes) { System.out.println(" " + parameterType); } System.out.println("该构造方法可能抛出的异常类型:"); Class<?>[] exceptionTypes = con.getExceptionTypes(); for (Class<?> exceptionType : exceptionTypes) { System.out.println(" " + exceptionType); } Book book = null; while (book == null) { try { if (i == 1) { book = (Book) con.newInstance("Java 教程", 10); } else if (i == 2) { book = (Book) con.newInstance(); } else { Object[] parameters = new Object[]{new String[]{"100", "200"}}; book = (Book) con.newInstance(parameters); } } catch (Exception e) { System.out.println("在创建对象时拋出异常,下面执行 setAccessible() 方法"); con.setAccessible(true); } } book.print(); System.out.println("=============================="); } } }
|
实验结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| 查看是否允许带可变数量的参数:true 该构造方法的入口参数类型依次为: class [Ljava.lang.String; 该构造方法可能抛出的异常类型: class java.lang.NumberFormatException name=null id=100 price=200 ==============================
查看是否允许带可变数量的参数:false 该构造方法的入口参数类型依次为: class java.lang.String int 该构造方法可能抛出的异常类型: name=Java 教程 id=10 price=0 ==============================
查看是否允许带可变数量的参数:false 该构造方法的入口参数类型依次为: 该构造方法可能抛出的异常类型: 在创建对象时拋出异常,下面执行 setAccessible() 方法 name=null id=0 price=0 ============================== Disconnected from the target VM, address: '127.0.0.1:44308', transport: 'socket'
Process finished with exit code 0
|