反射能干什么?你只需要给我一个class,我就能知道类的全部信息(类名称、父类、继承的接口、方法、属性、甚至实例化并赋值),那么下面就分3步,让你了解反射知识!
第一步:我们顺便创建一个类。第二步:我们通过3种方式获得上一步的类的class。第三步:我们通过class干下面的事情 实例化对象获得类的信息,继承的接口、构造方法、成员变量、方法调用类的方法 第四步:了解反射的应用场景这次我们准备用了一个Customer类,我们把它当成反射的对象,我们希望通过反射获取它的全部信息,我们先来看看这个类吧!
Customer类(类路径下面需要): 有一个无参数构造方法和一个private的构造方法(注意,下面要用)为了方便后面测试效果,实现了Person接口 package com.bridge.security.util.bean; /** * @创建人 zhangtaiyuan * @创建时间 2019/7/2 * @描述 */ public class Customer implements Person{ private String name; private String email; private int age; public Customer() { } private Customer(String name, String email, int age) { this.name = name; this.email = email; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Customer{" + "name='" + name + '\'' + ", email='" + email + '\'' + ", age='" + age + '\'' + '}'; } } 什么也没做的Person接口 package com.bridge.security.util.bean; public interface Person { }上面准备好了,我们就可以通过反射获取Customer类信息了
获得对象信息之前,我们必须获得Class,然后从Class中获取类对应的信息,获取Class有3种方法,如下:
通过实体类获得 Customer customer = new Customer() ; // 已经存在有指定类的实例化对象 Class<? extends Customer> cls = customer.getClass() ; System.out.println(cls.getName()); //输出结果:com.bridge.security.util.bean.Customer 直接从XXX.class获得 Class<? extends Customer> cls = Customer.class; System.out.println(cls.getName()); //输出结果:com.bridge.security.util.bean.Customer 从类的路径获得 Class<?> cls = Class.forName("com.bridge.security.util.bean.Customer") ; System.out.println(cls.getName());//输出结果:com.bridge.security.util.bean.Customer上面3个方式获得的Class都一样,最后一个通过传入String就能获得Class对象,是不是让我们想起了JDBC,哈哈
PS: 看着上面,你是不是明白了,如果没有反射,那么工厂模式创建实现类时,就会出现很多判断语句,并且当有新的工厂的实现类时,你就得修改代码并且升级版本,所以,没有反射,就只能使用简单工厂模式的方式实现了。
下面是例子
获得全部构造方法 Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ; for (Constructor<?> constructor:clazz.getDeclaredConstructors()){ //获得所有构造方法,包括非公开的 Customer中有个private方法 System.out.println(constructor.getName() + Arrays.toString(constructor.getParameterTypes())); } /** * 下面是输出结果 * com.bridge.security.util.bean.Customer[] * com.bridge.security.util.bean.Customer[class java.lang.String, class java.lang.String, int] */ 获得指定构成方法 Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ; System.out.println(clazz.getDeclaredConstructor().getName() + Arrays.toString(clazz.getDeclaredConstructor().getParameterTypes())); //下面是获得private 的够着方法 System.out.println(clazz.getDeclaredConstructor(String.class,String.class,int.class).getName() + Arrays.toString(clazz.getDeclaredConstructor(String.class,String.class,int.class).getParameterTypes())); /** * 输出结果: * com.bridge.security.util.bean.Customer[] * com.bridge.security.util.bean.Customer[class java.lang.String, class java.lang.String, int] */ 获得公开的(public)构造方法,下面就没有private构造方法了 Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ; for (Constructor<?> constructor:clazz.getConstructors()){ //获得所有构造方法,包括非公开的 Customer中有个private方法 System.out.println(constructor.getName() + Arrays.toString(constructor.getParameterTypes())); } /** * 下面是输出结果 * com.bridge.security.util.bean.Customer[] */ 获得指定的公开的构造方法,如果尝试去获得private的构造方法,就会直接报错 Class<?> clazz = Class.forName("com.bridge.security.util.bean.Customer") ; System.out.println(clazz.getConstructor().getName() + Arrays.toString(clazz.getConstructor().getParameterTypes())); //下面是获得private 的够着方法 System.out.println(clazz.getConstructor(String.class,String.class,int.class)); /** * 输出结果: * com.bridge.security.util.bean.Customer[] * Exception in thread "main" java.lang.NoSuchMethodException: com.bridge.security.util.bean.Customer.<init>(java.lang.String, java.lang.String, int) * at java.base/java.lang.Class.getConstructor0(Class.java:3322) * at java.base/java.lang.Class.getConstructor(Class.java:2108) * at com.bridge.security.util.bean.TestDemo.main(TestDemo.java:16) */打印结果
全部成员属性:[private java.lang.String com.bridge.security.util.bean.Customer.name, private java.lang.String com.bridge.security.util.bean.Customer.email, private int com.bridge.security.util.bean.Customer.age] 指定成员属性:private java.lang.String com.bridge.security.util.bean.Customer.name 全部公开成员属性:[] Exception in thread "main" java.lang.NoSuchFieldException: name at java.base/java.lang.Class.getField(Class.java:1958) at com.bridge.security.util.bean.Demo.main(Demo.java:12)注意
另外还有一个获取本地或者匿名类的方法,没有做深入的研究了获得Method方法后,还可以获得方法的返回值、参数、Annotation等信息另外需要注意反射是不能获得方法的参数的名称的 Method met = clazz.getDeclaredMethod("getAddress"); Modifier.toString(met.getModifiers()) ; // 修饰符 met.getReturnType().getName();//返回类型名称 met.getName();//方法名称 met.getParameterTypes(); // 获取参数类型 met.getExceptionTypes() ; //获得异常值 met.getAnnotations();//Annotations注解反射提供了另外一种设计思路,
工厂模式:很多框架软件里都能看到它应用场景,比如:JDBC,另外,动态代理:充分利用了反射的技术,让开发人员减轻了不少代码工作量。