一、反射机制的概述
1、什么是反射机制
动态获取信息以及动态调用对象的方法的功能称为Java语言的反射机制
简单来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息,包括: 访问修饰符、父类、实现的接口、属性和方法的所有信息,并可在运行时创建对象、修改属性(包括私有的)、调用方法(包括私有的)。
2、提供的功能
*在运行时判断一个对象所属的类
*在运行时构造任意一个类的对象
*在运行时判断一个类所具有的成员变量和方法
*在运行时调用任意一个对象的方法
3、作用
首先简单了解两个概念
*静态编译:在编译时确定类型,绑定对象,如:Student stu=new Student(“zhang”,30);
*动态编译:运行时才确定类型,绑定对象。如:Class.forName(“com.mysql.jadb.Driver.class”).newInstance();(后续介绍这个创建对象的语法)
动态编译最大限度发挥了java的灵活性,体现了多态的应用,用以降低类之间的耦合性。
而反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE中。它的缺点是对性能有影响。使用反射基本上是一种解释操作,这类操作总是鳗鱼直接执行的相同操作。
二、Class对象
1、class对象是Reflection故事起源。想要操作类中的属性和方法,都必须从class对象开始
*类是程序的一部分,每个类都有一个class对象。每当编写并且编译一个新类,就产生与之对应的一个Class对象。
*Class类没有公共构造方法。Class对象在加载类时由java虚拟机及通过调用类加载器中的方法自动构造,因此不能显式声明一个Class对象
2、获取Class对象的方式
*object.getClass()---获得指定实例的Class对象
*class.getSuperClass---获得当前Class的继承类的class
*.Class语法---.Class直接获取
*Class.forName(类名)---用得较多,用Class的静态方法,传入类的全称即可
*Primitive.TYPE---基本数据类型的包装类获取Class方式
三、JAVA反射API
1、java.lang包:
*Class<T>:表示一个正在运行的Java应用程序中的类和接口,是reflection的起源
2、java.lang.reflect包:
*Field类:代表成员变量(类的属性)
*Method类:代表类的方法
*Constructor类:代表类的构造方法。
*Array类:提供了动态创建数组,以及访问数组的元素的静态方法
四、通过反射实例化对象
1、实例化无参构造函数的两种方式:
*class.newInstance(); //通过Class对象的newInstance()方法直接创建对象,这种实例化对象的方式会默认调用无参的构造方法
*class.getConstructor(new Class[]{}).newInstance(new Object[]{}) //通过Class对象的getConstructor方法获得对应的构造方法,再通过返回的constructor对象的newInstance()创建实例
2、实例化带构造函数的对象
*class.getConstructor(Class<?>...parameterTypes).newInstance(Object...intargs)
五、通过反射获取并调用方法
1、获得当前类及超类所有的public Method
*Method[] arrMethods=classType.getMethods();
2、获得当前类及超类指定的public Method
*Method methods=classType.getMethod(String name,Class<?>...parameterTypes);
3、获得当前类声明的所有Method
*Method[] arrMethods=classType.getDeclareMethods();
4、获得当前类声明的指定的Method
*Method methods=classType.getDeclareMethods(String name,Class<?>...parameterTypes);
5、通过反射动态运行指定Method
*Object obj=method.invoke(Object object,Object...args)
六、通过反射获取并调用方法
1、获得当前类及超类所有的public Field
*Field[] arrFields=classType.getFields();
2、获得当前类及超类指定的public Method
*Field[] Field=classType.getFields(String name);
3、获得当前类声明的所有Method
*Field[] arrFields=classType.getDeclareFields();
4、获得当前类申明的指定的Method
*Field Field=classType.getDeclareFields(String name);
5、通过反射动态设定Field的值
*Field.set(Object object,Object values)
6、通过反射动态获得Field的值
*Field.get(Object object)
七、案例
1、使用反射机制的步骤:
*获得类对应的Class对象
*通过Class对象,调用相关的构造方法创建类的对象
*通过反射来调用方法或属性
2、案例代码
package com.huanbao.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectionDemo{
public static void main(String[] args) throws Exception {
//获得Employee类关联的Class对象
Class<?> classType=Class.forName("com.huanbao.reflection.Employee");
//通过反射机制来构造Employee的实例对象(默认调用无参的构造方法)
Employee employee=(Employee) classType.newInstance();
//调用指定的构造方法来构造对象(同样调用无参构造方法)
Constructor<?> constructor=classType.getConstructor(new Class[] {});
Employee employee1=(Employee) constructor.newInstance(new Object[] {});
//调用指定的构造方法来构造对象(调用带参数的构造方法)
constructor=classType.getConstructor(new Class[] {String.class,int.class});//参数类型所对应的class对象
Employee employee2=(Employee) constructor.newInstance(new Object[] {"zhangsna",30});
//获取Class对象所有的方法,包括私有的,然后输出方法名作测试
Method[] methods=classType.getDeclaredMethods();
for(Method method:methods) {
System.out.println(method.getName());
}
//获取Class对象所指定的方法,包括私有的,然后打印输出方法名作测试
Method method=classType.getDeclaredMethod("toString", new Class[] {});
System.out.println(method.getName());
//方法的调用(调用toString方法)
String test=(String) method.invoke(employee, new Object[] {});
System.out.println(test);
//获取Class所指定的属性,包括私有的
Field field=classType.getDeclaredField("name");
field.setAccessible(true);//由于是私有的,必须要设置访问权限,才可以实现属性的操作
field.set(employee, "王五");
System.out.println(field.get(employee));
}
}
class Employee{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Employee() {
System.out.println("无参构造方法");
}
public Employee(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Employee [name=" + name + ", age=" + age + "]";
}
}