Java的反射机制:是指允许程序员在程序运行的时候可以获取到某个类内部的信息(变量,方法,构造方法等),并且可以对其进行修改。
目录
一、通过反射机制获取Class类。
Class类:JVM将class字节码文件加载到内存中,会将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个该类的Class类对象,作为方法区的访问入口。(类的加载机制)
我们所定义的所有类,都是Class类的实例对象。那么Class的内部是什么样子呢。就可以使用java的反射机制获取Class类。
public class ReflectionDemo { public static void main(String[] args) { // 获取Class类对象的方式:通过类名 Class c1 = User.class; System.out.println(c1); // 获取Class类对象的方式:通过对象 User user = new User(); Class c2 = user.getClass(); System.out.println(c2); // 获取Class类对象的方式 try { Class c3 = Class.forName("reflection.User");//使用的是User类在项目中的完整路径 System.out.println(c3); }catch (ClassNotFoundException e){ e.printStackTrace(); } } }
二、通过反射机制获取类的方法/属性/父类/接口
public class ReflectionDemo2 { public static void main(String[] args) { User user = new User(); printClassMethod(user); } public static void printClassMethod(Object object){ //1、获取入参类的类型 Class c = object.getClass(); //2、获取入参类的名字 String cName = c.getName(); System.out.println("入参类的名字是:" + cName); //3、获取入参了类内部方法 Method[] ms = c.getMethods(); for(int i = 0; i < ms.length; i++){ // 第一步,获取方法的返回值类型的类类型 Class returnType = ms[i].getReturnType(); System.out.println(returnType.getName() + " "); // 第二步,获取方法的名称 String className = ms[i].getName(); System.out.println(className + "("); // 第三步,获取方法参数类型 Class[] paramTypes = ms[i].getParameterTypes(); for(Class paramType : paramTypes){ System.out.println(paramType + ","); } System.out.println(")"); } } }
1、获取方法的方法:
c.getMethods(); // 获取所有public的饿啊很熟,包括从父类继承来的 c.getMethod("getName"); // 返回方法名为getName的方法 c.getDeclaredMethods(); // 获取该类所有自己声明的方法,不管什么访问权限 c.getDeclaredMethod("getName");// 返回一个自己声明的且方法名为getName的方法
2、获取属性的方法:
c.getDeclaredFields(); c.getDeclaredField("name"); c.getField("name"); // 访问控制符必须是public
3、获取类的父类/接口
c.getSuperclass(); c.getInterfaces();
三、使用反射机制
1、通过反射机制了解泛型的本质
Java集合中的泛型是为了防止错误的输入,只在编译过程有效,只要绕过了编译,就无效了。
public class Reflection1 { public static void main(String[] args) { int number = 1; ArrayList<String> list1 = new ArrayList<>(); ArrayList list2 = new ArrayList(); // list1.add(number); list2.add(number); Class c1 = list1.getClass(); Class c2 = list2.getClass(); System.out.println(c1 == c2); try{ Method m = c2.getMethod("add", Object.class); m.invoke(list1,number); System.out.println(list1); }catch (Exception e){ System.out.println("异常了"+ e ); } } }
编译过程中,如果list1中增加了非String类型的数据,会报错,但是通过反射在运行期间对list1期间进行添加,则可以正常插入。
2、Spring中的使用
学习Spring的时候,我们知道Spring主要有AOP和IOC两大思想,它利用的就是反射机制。
对于Spring的核心AOP来说,使用了动态代理,其实底层也是反射。
面试相关问题:项目中的反射机制的使用?
读取外部Excel文件,将文件中的字段赋值到具体类中,通过反射机制获取set方法并赋值。
public static void generateModel(Object obj, String filedName, String value) throws Exception { // 获取这个类中和这个字段相关的信息 Field field = obj.getClass().getDeclaredField(filedName); // 设置这个字段可以被赋值 默认不能赋值 field.setAccessible(true); transFieldValue( obj, field, value); } public static void transFieldValue(Object model, Field field, String value) throws Exception { // 获取字段名,将字段名的首字符大写,方便构造get,set方法 String name = field.getName(); name = name.substring(0, 1).toUpperCase() + name.substring(1); String type = field.getGenericType().toString(); if (type.equals("class java.lang.String")) { Method m = model.getClass().getMethod("set"+name,String.class); if (StringUtil.isNotBlank(value.trim())) { m.invoke(model, value); return; } }else if (type.equals("class java.lang.Integer")) { Method m = model.getClass().getMethod("set"+name,Integer.class); if (StringUtil.isNotBlank(value.trim())) { m.invoke(model, Integer.parseInt(value)); return; } }else if (type.equals("class java.lang.Short")) { Method m = model.getClass().getMethod("set"+name,Short.class); if (StringUtil.isNotBlank(value.trim())) { m.invoke(model, Short.parseShort(value)); return; } }else if (type.equals("class java.lang.Double")) { Method m = model.getClass().getMethod("set"+name,Double.class); if (StringUtil.isNotBlank(value.trim())) { m.invoke(model, Double.parseDouble(value)); return; } }else if (type.equals("class java.math.BigDecimal")) { Method m = model.getClass().getMethod("set"+name,BigDecimal.class); if (StringUtil.isNotBlank(value.trim())) { m.invoke(model, new BigDecimal(value)); return; } }else if (type.equals("class java.lang.Boolean")) { Method m = model.getClass().getMethod("set"+name,Boolean.class); if (StringUtil.isNotBlank(value.trim())) { m.invoke(model, Boolean.parseBoolean(value)); return; } }else if (type.equals("class java.util.Date")) { Method m = model.getClass().getMethod("set"+name,Date.class); if (StringUtil.isNotBlank(value.trim())) { SimpleDateFormat sdf_long = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); SimpleDateFormat sdf_short = new SimpleDateFormat("yyyy-MM-dd"); Date date; if (value.length() > 10){ date = sdf_long.parse(value); }else { date = sdf_short.parse(value); } m.invoke(model, date); return; } } }