JAVA 反射
一、什么是反射?
能够分析类能力的程序 称之为反射
二、反射能做什么?
反射机制的功能极其强大,打个比方,假如你有反射功能,那么你不管看到谁,都可以看透对方的一切,并且还可以调用对方的肢体做一些你想做的事情。
三、怎么反射?
1. 利用Class对象来反射
每当编译一个类,便会生成一个同名的.class文件,此文件中保存了类相关的信息,称之为Class对象。
每当程序需要实例化一个对象时(或者是创建静态成员的引用时),JVM将使用类加载器来载入这个类的Class对象,再用Class对象来创建这个对象
可以这么理解:每一个类都有自己的class对象,class对象是保存在文件中的,在使用的时候会被加载到JVM中,class对象是用来创建对象的模板。
2. 得到Class
第一种方式:
//一般来说 这种方式几乎不会使用 User user = new User(); Class c1 = user.getClass();
第二种方式:
//在程序中反射某个类的信息时一般会使用这种方式 Class c2 = User.class;
第三种方式:
//当类路径从配置文件加载的时候会使用此种方式 try{ //无论何时使用这种方式必须提供一个错误处理器 Class c3 = Class.forName("model.User"); }catch (ClassNotFoundException e){ System.out.println("类不存在"); }
3. 根据Class获取对象实例
Class c1 = User.class; try{ Object object = c1.newInstance();//调用无参构造器 必须是显式构造器 User user = (User) object; System.out.println(user.toString()); }catch (Exception e) { e.printStackTrace(); }
四、实现反射
1. 反射构造函数
Class cla = User.class; Constructor[] constructors = cla.getConstructors();//获取当前类的所有public构造函数 //Constructor[] constructors = cla.getDeclaredConstructors();//获取当前类的所有构造函数 Arrays.stream(constructors).forEach((v)->{ System.out.print(Modifier.toString(v.getModifiers()) + " " + v.getName() + "("); String string = Arrays.stream(v.getParameterTypes()).map(Class::getName).collect(Collectors.joining(",")); System.out.println(string + ")"); });
2. 反射属性
Class cla = User.class; //Field[] fields = cla.getFields();//获取当前类包括超类的public属性 Field[] fields = cla.getDeclaredFields();//获取当前类的所有属性 包括私有属性 Arrays.stream(fields).forEach((v)->{ String s = Modifier.toString(v.getModifiers()) + " " + v.getType().getName() + " " + v.getName(); try{ s += " = " + v.get(cla.newInstance()); }catch (Exception e){ }finally { System.out.println(s); } });
3. 反射方法
Class cla = User.class; //Method[] methods = cla.getMethods();//获取当前对象包括超类对象包括Object对象的所有public方法 Method[] methods = cla.getDeclaredMethods();//获取当前对象的所有方法 包括私有方法 Arrays.stream(methods).forEach((v)->{ //Type type = v.getGenericReturnType();//与getReturnType一样 Type type = v.getReturnType(); System.out.print(type.getTypeName()+" "+v.getName() + "("); Class[] params = v.getParameterTypes(); String string = Arrays.stream(params).map(Class::getName).collect(Collectors.joining(",")); System.out.println(string + ")"); });
4. 反射注解
Class cla = User.class; //获取类上的注解 Annotation[] annotations = cla.getAnnotations(); Arrays.stream(annotations).forEach(System.out::println); if(cla.isAnnotationPresent(Deprecated.class)){ System.out.println(cla.getName()+"类含有Deprecated这个注解"); } System.out.println("-----------------"); //获取方法上的注解 Method[] methods = cla.getDeclaredMethods(); Arrays.stream(methods).filter((v)->v.getDeclaredAnnotations().length > 0).forEach((vvv)-> { Annotation[] a2 = vvv.getDeclaredAnnotations(); System.out.print(vvv.toString() + ": "); Arrays.stream(a2).forEach(System.out::println); if(vvv.isAnnotationPresent(Transient.class)){ System.out.println(vvv.getName()+"方法含有Transient这个注解"); } });
我们在spring框架中时常用到@Controller @Service @Autowrite 等注解 实际上框架就是在启动的时候利用反射技术将所有类所有方法遍历了一遍 校验是否含有注解 根据不同的注解初始化不同的事情
关于注解的内容会另外开一篇博客系统阐述,在此只是说明注解存在的意义是被反射发现,这也是注解唯一的用处。
5. 调用方法
Class cla = User.class; try{ //调用某个类的某个方法 User user = (User)cla.newInstance(); Method method1 = cla.getMethod("setId", Long.class); method1.invoke(user,2L); Method method11 = cla.getMethod("getId"); System.out.println(method11.invoke(user)); //静态方法可传Null Method method2 = cla.getMethod("setSex", String.class); method2.invoke(null,"不男不女"); Method method22 = cla.getMethod("getSex"); System.out.println(method22.invoke(null)); }catch (Exception e){ e.printStackTrace(); }
五、源码分享