Java反射机制
微信文章
目标:
- 了解反射的基本原理
- 掌握Class类的使用
- 使用Class类并结合其他类取得一个类的完整结构
- 通过反射机制动态地调用类中的指定方法,并能向这些方法中传递参数
正常情况下如果有一个类,则肯定可以通过类创建对象;那么如果现在要求通过一个对象找到一个类的名称,此时就需要反射机制。
在反射操作的学习中,我会一直体会”一切的操作都将使用Object完成,类、数组的引用都可以使用Object进行接收”
认识Class类
Class类的功能:允许通过一个实例化对象找到一个类的完整信息
package classTest;
// 通过一个对象得到完整的”包.类”名称
public class Person {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) {
Person base = new Person( );
System.out.println(base.getClass().getName());
// 输出结果:classTest.Person
}
}
通过结果发现,通过一个对象得到了对象所在的完整的”包.类”名称,getClass是Object类中的方法( public final Class getClass() )
该方法的返回值是Class类,此类是Java反射的源头,即可以通过对象反射求出类的名称
在定义Class类时使用了泛型声明。Class类本身表示一个类的本身,通过Class可以完整地得到一个类中的完整结构,包括此类中的方法定义、属性定义等。
方法 | 描述 |
---|---|
public static Class forName(String className) | 传入完整的”包.类”名称实例化Class对象 |
public Constructor[] getConstructors() throws SecurityException | 得到一个类中的全部构造方法 |
public Field[] getDeclaredFields() throws SecurityException | 得到本类中单独定义的全部属性 |
public Field[] getFields() throws SecurityException | 得到本类继承而来的全部属性 |
public Method[] getMethods() throws SecurityException | 得到一个类中的全部方法 |
public Method getMethod(String name, Class… parameterTypes) throws NoSuchMethodException,SecurityException | 返回一个Method对象,并设置一个方法中的所有参数类型 |
public Class[] getInterfaces() | 得到一个类中所实现的所有接口 |
public String getName() | 得到一个完整的”包.类”名称 |
public Package getPackage() | 得到一个类的包 |
public Class getSuperclass() | 得到一个类的父类 |
public Object newInstance() throws InstantiationException,IllegalAccessException | 根据Class定义的类实例化对象 |
public Class getConponentType() | 返回表示数组类型的Class |
public boolean isArray() | 判断此Class是否是一个数组 |
package classTest;
// 实例化Class类对象
public class Person {
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) {
Class
Class类的使用
上面说了Class类的实例化过程,那么到底该怎么用Class类呢?实际上Class类在开发中最常见的用法就是实例化对象的操作,即通过一个给定的字符串来实例化一个类的对象。
通过无参构造器实例化对象
通过Class类本身实例化其他类的对象,可以使用newInstance()方法,但是必须保证被实例化的类中存在一个无参构造方法
package classTest;
// 通过Class类实例化对象
public Class Person {
private String name;
private int age;
// getter、setter方法
// 重写toString方法
public static void main(String[] args) {
Class
通过有参构造器实例化对象
如果一定要通过有参构造器实例化对象,Java也提供了实现
1. 通过Class类中的getConstructors()取得本类中的全部构造方法
2. 向构造方法中传递一个对象数组进去,里面包含了构造方法中所需要的各个参数
3. 之后通过Constructor实例化对象
使用了Constructor类,表示构造方法
方法 | 描述 |
---|---|
public int getModifiers() | 得到构造方法的修饰符 |
public String getName() | 得到构造方法的名称 |
public Class[] getParameterTypes() | 得到构造方法中参数的类型 |
public String toString() | 返回此构造方法中的信息 |
public T newInstance(Object… initargs) throws XXXException | 向构造方法中传递参数,实例化对象 |
- 得到本类中的所有构造器
- 选择第N个构造器,调用newInstance方法并传入M个参数
- 注意: 需要知道构造器的顺序。而且编码较使用forName复杂。不建议使用
反射的应用–取得一个类的完整结构
可以通过反射得到一个类的完整结构,需要java.lang.reflect包中几个类(Constructor、Field、Method),它们都是AccessibleObject类的子类
取得所实现的全部接口
public Class[] getInterfaces()
1. 实例化对象
2. 取得本类实现的所有接口(数组)
3. 进行遍历
取得父类
public Class
取得全部构造方法
public Constructor[] getConstructors() throws SecurityException
1. 实例化对象
2. 取得全部的构造器(数组)
3. 遍历
4. 可以得到(构造方法的修饰符–权限、名称、参数的类型)
> 另:权限是数字,要还原为关键字,需要Modifier类(Modifier.toString(权限数字))
取得全部方法
方法 | 描述 |
---|---|
public int getMmodifiers() | 取得本方法的访问修饰符 |
public String getName() | 取得方法的名称 |
public Class[] getParameterTypes() | 得到方法的全部参数类型 |
public Class[] getReturnType() | 得到方法的返回值类型 |
public Class[] getExceptionTypes() | 得到一个方法的全部抛出异常 |
public Object invoke(Object obj, Object… args) throws 一堆Exception | 通过反射调用类中的方法 |
取得全部属性
public Field[] getFields() throws SecurityException // 得到实现的接口或父类中的公共属性
public Field[] getDeclaredFields() throws SecurityException // 得到本类中的全部属性
方法 | 描述 |
---|---|
public Object get(Object obj) throws 某Exception | 得到一个对象中属性的具体内容 |
public void set(Object obj, Oeject value) throws 某Exception | 设置指定对象中属性的具体内容 |
public int getModifiers() | 得到属性的修饰符 |
public String getName() | 得到属性的名称 |
public boolean isAccessible() | 判断此属性是否可被外部访问 |
public void setAccessible(boolean flag) throws 某Exception | 设置一个属性是否可被外部访问(打开访问权限) |
public static void setAccessible(AccessibleObject[] array, boolean flag) throws 某Exception | 设置一组属性是否可被外部访问 |
public String toString() | 得到此Field类的信息 |
反射的应用–通过反射完整对数组的操作
代码片
通过反射调用类中的方法
- 通过Class类的getMethod(String name, Class… parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型
- 使用invoke进行调用,并向方法中传递要设置的参数