反射相关

1.反射的定义

反向探知,在程序运行过程中动态的获取类的相关属性

这种动态获取类的内容以及动态调用对象的方法和获取属性的机制.就叫做JAVA的反射机制

反射的优缺点

优点

增加程序的灵活性,避免固有逻辑写死到程序中

代码相对简洁,可以提高程序的复用性

缺点

相比于直接调用反射有比较大的性能销毁

内部暴露和安全隐患

反射到底慢在哪里?

1.调用了native方法

2.每次newInstance都会做安全检查 比较耗时

 

2.反射的操作

2.1基本操作

1.获取类对象的四种方式

// 获取类对象的四种方式
Class<User> clazz1 = User.class;
Class<?> clazz2 = Class.forName("com.gupao.edu.fs.User");
Class<? extends User> clazz3 = new User().getClass();
Class<?> clazz4 = Demo03.class.getClassLoader().loadClass("com.gupao.edu.fs.User");

 

 

2.基本信息操作

// 获取类的相关结构
System.out.println(clazz1.getModifiers()); // 获取类的修饰符
System.out.println(clazz1.getPackage());
System.out.println(clazz1.getName());
System.out.println(clazz1.getSuperclass());
System.out.println(clazz1.getClassLoader());
System.out.println(clazz1.getSimpleName());
System.out.println(clazz1.getInterfaces().length); // 获取类似实现的所有的接口
System.out.println(clazz1.getAnnotations().length);

 

 

2.2字段的操作

   /**
    * Field操作
    * @param args
    */
   public static void main(String[] args) throws Exception {
       Class<User> userClass = User.class;
       // 获取User对象
       User user = userClass.newInstance();
       // 获取类型中定义的字段 共有的字段以及父类中共有的字段
       Field[] fields1 = userClass.getFields();
       for(Field f:fields1){
           System.out.println(f.getModifiers() + " " + f.getName());
      }
       System.out.println("--------------------");
       // 可以获取私有的字段 只能够获取当前类中
       Field[] fields2 = userClass.getDeclaredFields();
       for(Field f:fields2){
           System.out.println(f.getModifiers() + " " + f.getName());
      }

       // 获取name字段对应的Field
       Field nameField = userClass.getDeclaredField("name");
       // 如果要修改私有属性信息那么我们需要放开权限
       nameField.setAccessible(true);
       nameField.set(user,"咕泡");
       System.out.println(user.getName());
       // 如果对静态属性赋值
       Field addressField = userClass.getDeclaredField("address");
       addressField.set(null,"湖南长沙");
       System.out.println(User.address);

  }

2.3 类中的方法操作

    public static void main(String[] args) throws Exception {
       User user = new User();
       Class<User> userClass = User.class;
       // 可以获取当前类及其父类中的所有的共有的方法
       Method[] methods = userClass.getMethods();
       for (Method m : methods) {
           System.out.println(m.getModifiers() + " " + m.getName());
      }
       System.out.println("**********");
       // 获取本类中的所有的方法 包括私有的
       Method[] declaredMethods = userClass.getDeclaredMethods();
       for (Method m:declaredMethods){
           System.out.println(m.getModifiers() + " " + m.getName());
      }
       Method jumpMethod = userClass.getDeclaredMethod("jump");
       // 放开私有方法的调用
       jumpMethod.setAccessible(true);
       jumpMethod.invoke(user);
       Method sayMethod = userClass.getDeclaredMethod("say", String.class);
       // 静态方法调用
       sayMethod.invoke(null,"咕泡666");
  }

 

2.4 构造器的操作

    /**
    * 构造器的操作
    * @param args
    */
   public static void main(String[] args) throws Exception {
       Class<User> userClass = User.class;
       // 获取所有的公有的构造器
       Constructor<?>[] constructors = userClass.getConstructors();
       for (Constructor c:constructors){
           System.out.println(c.getModifiers() + " " + c.getName() );
      }
       System.out.println("************************");
       // 获取所有的构造器
       Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();
       for (Constructor c:declaredConstructors){
           System.out.println(c.getModifiers() + " " + c.getName() );
      }
       // 1.直接通过newInstance创建对象
       User user = userClass.newInstance();
       // 2.获取对应的Construcator对象获取实例
       Constructor<User> declaredConstructor = userClass.getDeclaredConstructor(String.class, String.class);
       // 私有的构造器调用需要放开权限
       declaredConstructor.setAccessible(true);
       System.out.println(declaredConstructor.newInstance("gupao","男"));


  }

 

 

3.单例的漏洞

产生的原因是:反射可以调用私有的构造器造成的

public class PersonSingle {

   private static PersonSingle instance;

   private PersonSingle(){
       if(instance != null){
           throw new RuntimeException("实例已经存在了,不允许再创建...");
      }
  }

   public static PersonSingle getInstance(){
       if(instance == null){
           instance = new PersonSingle();
      }
       return instance;
  }
}

 

解决方案:在私有构造其中加入逻辑判断结合RuntimeException处理即可

    public static void main(String[] args) throws Exception {
       PersonSingle p1 = PersonSingle.getInstance();
       PersonSingle p2 = PersonSingle.getInstance();
       PersonSingle p3 = PersonSingle.getInstance();
       System.out.println(p1);
       System.out.println(p2);
       System.out.println(p3);
       // 通过反射获取实例
       Constructor<? extends PersonSingle> declaredConstructor = p1.getClass().getDeclaredConstructor();
       declaredConstructor.setAccessible(true);
       System.out.println( declaredConstructor.newInstance());

  }

 

 

反射的使用场景:

1.jdbc封装

2.SpringIOC

3.JdbcTemplate

4.Mybatis

....

 

 

4.反射的应用 SpringIOC

IOC 控制反转 就是一种设计思想,容器 管理对象

try {
  // 创建对应IOC容器对象
           DefaultListableBeanFactory beanFactory = this.createBeanFactory();
           beanFactory.setSerializationId(this.getId());
           this.customizeBeanFactory(beanFactory);
  // 配置文件中的<bean> 会被解析封装为一个 BeanDefinition
           this.loadBeanDefinitions(beanFactory);
           Object var2 = this.beanFactoryMonitor;
           synchronized(this.beanFactoryMonitor) {
               this.beanFactory = beanFactory;
          }
      } catch (IOException var5) {
           throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
      }

 

 

// 加载配置问题  SAX
Document doc = this.doLoadDocument(inputSource, resource);
// 配置文件解析 BeanDefinition
return this.registerBeanDefinitions(doc, resource);

 

 

public void refresh() throws BeansException, IllegalStateException {
       Object var1 = this.startupShutdownMonitor;
       synchronized(this.startupShutdownMonitor) {
           this.prepareRefresh();
           // 创建IOC容器对象 BeanFactory 同时解析配置文件
           ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
           this.prepareBeanFactory(beanFactory);

           try {
               this.postProcessBeanFactory(beanFactory);
               this.invokeBeanFactoryPostProcessors(beanFactory);
               this.registerBeanPostProcessors(beanFactory);
               this.initMessageSource();
               this.initApplicationEventMulticaster();
               this.onRefresh();
               this.registerListeners();
               // 单例对象的实例化
               this.finishBeanFactoryInitialization(beanFactory);
               this.finishRefresh();
          } catch (BeansException var9) {
               if (this.logger.isWarnEnabled()) {
                   this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
              }

               this.destroyBeans();
               this.cancelRefresh(var9);
               throw var9;
          } finally {
               this.resetCommonCaches();
          }

      }
  }

 

 

    public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
       Assert.notNull(ctor, "Constructor must not be null");

       try {
           ReflectionUtils.makeAccessible(ctor);
           return ctor.newInstance(args);
      } catch (InstantiationException var3) {
           throw new BeanInstantiationException(ctor, "Is it an abstract class?", var3);
      } catch (IllegalAccessException var4) {
           throw new BeanInstantiationException(ctor, "Is the constructor accessible?", var4);
      } catch (IllegalArgumentException var5) {
           throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", var5);
      } catch (InvocationTargetException var6) {
           throw new BeanInstantiationException(ctor, "Constructor threw exception", var6.getTargetException());
      }
  }

 

posted @ 2022-02-08 11:47  小白冲  阅读(212)  评论(0编辑  收藏  举报