1、概念
优点:
用于开发时项目分组的情况下,提前模拟类,方法项目进度使用
提高开发灵活度,提高程序的扩展性
缺点:
破坏封装,性能低下
2、常用方法
1. 获取字节码文件
1. Class clazz = Class.forName(全限定路径名) (最多使用)
static 类<?> forName(String name, boolean initialize, ClassLoader loader)
使用给定的类加载器返回与给定字符串名称的类或接口相关联的 类对象。
2. 全限定类名.class
3. 对象名.getClass()
2. 根据字节码文件获取构造方法、普通方法、字段等
构造方法
Constructor[] constructors = clazz.getConstructors() 获取public修饰的构造方法数组
Constructor[] constructors = clazz.getDeclaredConstructors() 获取所有造方法数组
Constructor constructor = clazz.getConstructor(Class 参数字节码)根据参数类型获取指定的的构造方法
//通过构造方法对象去用构造方法创建对象 => 相当于new 一个对象
Object instance = constructor.newInstance(Object 实参);
普通方法
Method[] methods = clazz.getMethods() 获取public修饰的普通方法数组
Method[] methods = clazz.getDeclaredMethods() 获取所有普通方法数组
Method method = clazz.getMethod(String methodName,Class... 参数字节码)根据方法名和参数类型获取指定的的方法
如果方法没有形参,则Class可变参数不用写
//通过普通方法对象调用执行方法
method.invoke(Object 对象,Object... args);
如果是对象的方法,对象就是上面创建的instance,如果是static方法,则写null
args:就是具体实参
字段
Field[] fields = clazz.getFields() 获取public修饰的字段数组
Field[] fields = clazz.getDeclaredFields() 获取所有权限的字段数组
Field field = clazz.getDeclearField(String fieldName) 根据字段名获取指定字段
Field field = clazz.Field(String fieldName)根据字段名获取指定public修饰字段
//通过当前的字段对象,给某一个字段赋值取值
field.get(Object obj);
field.set(Object obj, Object value);
String getName() 获取全限定类名(全限定,包含包名)
String getSimpleName() 获取类名简称
Package getPackage() 获取包名
* 注意事项:
* T newInstance() 根据当前字节码创建对应的对象,只能创建无参构造的对象
3、具体代码实现
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 通过反射操做对象
*/
public class ReflectTest2 {
public static void main(String[] args) throws Exception {
//拿到字节码文件(根据完全限定名)
Class<?> clazz = Class.forName("cn.itsource.reflect.User");
/*
* 构造方法
*/
//获取到所以的构造方法,包括私有化的(通过传入的参数类型字节码,获取到对应的构造方法)
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class,int.class,boolean.class);
//如果参数是true,破坏封装性。得到私有化的构造方法
//constructor.setAccessible(true);
//传入具体的参数(给字段设置值),得到实例对象
Object instance = constructor.newInstance("张三",20,true);
/*
* 字段
*/
//通过字节码对象,获取到所有的字段 (里面传入类里面参数的具体名称)
Field field = clazz.getDeclaredField("name");
//破坏封装,得到private修饰的字段。如果是public修饰的,就不需要写
field.setAccessible(true);
//给字段设置值。参数1:需要操作的是哪个实例对象里面的字段(如果该字段是static修饰的,那么参数一就可以写:null),参数2:具体的值
field.set(instance, "李四");
//获取的字段的值(根据传入的实例对象获取对应的字段值)
Object object = field.get(instance);
System.out.println("字段:"+object);
/*
* 普通方法
*/
//通过字节码对象,获取里面所有的方法(参数1:方法名称 参2:该方法内,参数类型的字节码(可变参数,可以写多个))
Method method = clazz.getDeclaredMethod("add",String.class,int.class);
//通过方法的对象,调用里面的方法 参数1:需要操作的类(实例对象)如果该方法是static修饰的,那么参数1是可以写null 参数2:具体的值,可变参数可以写多个(没有就不写)
Object invoke = method.invoke(instance, "具体的值",1);
System.out.println("方法:"+invoke);
//获取完全限定名
String name = clazz.getName();
System.out.println("完全限定名:"+name);
//获取到简写的名字
String simpleName = clazz.getSimpleName();
System.out.println("简写:"+simpleName);
}
}