反射可以做到的事情
- 在不修改源码的情况下,通过配置文件来控制程序
- 在程序运行的时候,通过反射动态创建对象,并且可以操作对象的所有属性、方法、构造器
- 生成动态代理
反射重要的4个类
- java.lang.Class
- java.lang.reflect.Field
- java.lang.reflect.Method
- java.lang.reflect.Constructor
Class类
一个类在堆中只有一个Class对象,这个Class对象包含了类的完整结构信息
在使用反射的过程中,把方法、属性、构造器都当做对象来处理的
Class类对象由系统创建,继承了Object类
Class类的类图
Class类常用方法
//1.通过全路径 获取对应的Class对象 String classAllPath = "com.java.test.Student"; Class<?> cls = Class.forName(classAllPath); //2.获取包名 String packageName = cls.getPackage().getName(); //3.获取全类名 String classFullName = cls.getName(); //4.通过Class对象创建对应对象的实例 Object obj = cls.newInstance(); //5.获取public修饰的属性,并设置值 Field nameField = cls.getField("name"); String nameValue = nameField.get(obj).toString(); nameField.set(obj,"jack"); System.out.println(nameField.get(obj)); //jack //6.获取所有public修饰的属性(字段) Field[] fields = cls.getFields(); for (Field field : fields) { System.out.println(field.getName()); } //7.获取所有属性,包括私有属性 Field[] declaredFields = cls.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField.getName()); }
获取Class类对象4种方式
- Class.forName( )
- 类名.class
- 对象名.getClass( )
- 类加载器获取Class对象
//1.通过Class类的静态方法forName()获取 String classAllPath = "com.java.test.Student"; Class<?> cls = Class.forName(classAllPath); //2.类名.class Class<String> stringClass = String.class; //3.对象名.getClass():通过已经创建好的对象,获取Class对象 String str = new String("hello"); Class<? extends String> aClass = str.getClass(); //4.通过类加载器来获取类的Class对象 ClassLoader classLoader = str.getClass().getClassLoader(); //ClassLoader classLoader = String.class.getClassLoader(); Class<?> strClassObject = classLoader.loadClass("java.lang.String");
基本数据类型的Class类对象和包装类的Class类对象
//byte short int long float double char boolean Class<Byte> byteClass = byte.class; Class<Short> shortClass = short.class; Class<Integer> integerClass = int.class; Class<Long> longClass = long.class; Class<Float> floatClass = float.class; Class<Double> doubleClass = double.class; Class<Character> characterClass = char.class; Class<Boolean> booleanClass = boolean.class; Class<Integer> type = Integer.TYPE; //其它包装类获取Class类对象的方式和Integer一样
Field类
- getField( )、getFields( )、getDeclaredFields( )
- getModifiers( ):返回修饰符
- getType( ):返回类型
- getName( ):返回属性名
//通过全路径 获取对应的Class对象 String classAllPath = "com.java.test.Student"; Class<?> cls = Class.forName(classAllPath); //获取所有属性对象,包括私有属性 Field[] declaredFields = cls.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField.getModifiers()+" "+ declaredField.getType()+" "+declaredField.getName()); }
Method类
- getMethod( )、getMethods( )、getDeclaredMethods( )
- getModifiers( ):返回方法的返回值类型
- getParameterTypes( ):返回参数类型的数组
- getName( ):返回方法的名称
//通过全路径 获取对应的Class对象 String classAllPath = "com.java.test.Student"; Class<?> cls = Class.forName(classAllPath); 获取所有方法对象,包括私有方法 Method[] declaredMethods = cls.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println(declaredMethod.getModifiers()+" "+declaredMethod.getReturnType()+" "+ Arrays.toString(declaredMethod.getParameterTypes())); }
Constructor类
- getConstructor( )、getConstructors( )、getDeclaredConstructors( )
- getModifiers( ):以int形式返回修饰符
- getName( ):返回构造器的全类名
- getParameterTypes( ):返回参数类型的数组
- setAccessible( ):爆破,访问私有成员
- newInstance( ):创建对象
//通过全路径 获取对应的Class对象 String classAllPath = "com.java.test.Student"; Class<?> cls = Class.forName(classAllPath); //获取所有的构造器对象,并且获取构造器对象的信息 Constructor<?>[] constructors = cls.getDeclaredConstructors(); for (Constructor<?> constructor : constructors) { System.out.println(constructor.getModifiers()+" "+constructor.getName() +" "+Arrays.toString(constructor.getParameterTypes())); } // 使用反射创建对象 // 无参构造器创建对象 Object o = cls.newInstance(); // 有参构造器创建对象 Constructor<?> constructor = cls.getConstructor(int.class, String.class); Object o2 = constructor.newInstance(1000, "hello"); // 私有有参构造器创建对象 Constructor<?> declaredConstructor = cls.getDeclaredConstructor(String.class); declaredConstructor.setAccessible(true); Object o3 = declaredConstructor.newInstance("jack");
反射的简单使用
/** 需求: 1.根据配置文件的信息创建对象 2.通过反射操作private修饰的属性的值,并调用对象的方法 */
propeties配置文件
classFullPath=com.java.reflection.Student name=jack method=sayHello
Student类
@Data public class Student { private String name; public void sayHello(){ System.out.println("hello "+name); } }
main( )方法
public static void main(String[] args) throws Exception { //1.使用Properties类读取Maven工程resources文件夹下的配置文件信息 //1.1读取配置文件到内存中 Properties properties = new Properties(); InputStream resourceAsStream = DemoTest.class.getResourceAsStream("/test.properties"); properties.load(resourceAsStream); //1.2获取配置文件信息 String classFullPath = properties.get("classFullPath").toString(); String nameProValue = properties.get("name").toString(); String methodPro = properties.get("method").toString(); //2.使用反射机制创建对象,并调用对象的方法和属性 Class<?> cls = Class.forName(classFullPath); //获取运行时类对象 Object obj = cls.newInstance();//根据类对象创建对应的实例对象 Method methodObj = cls.getMethod(methodPro);//获取方法的对象 //获取属性的对象,并设置属性值 Field fieldObj = cls.getDeclaredField("name"); fieldObj.setAccessible(true);//私有属性必须先爆破,才能设置值 fieldObj.set(obj,nameProValue); //通过方法对象调用方法 methodObj.invoke(obj);//hello jack }