• 反射相关


    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());
          }
      }

     

  • 相关阅读:
    一道关于js声明变量,var和let的面试题
    自执行匿名函数: (function() { /* code */ })();
    2017-09-26 开通博客第一天。 希望以后能够坚持更新,记录自己的成长,努力汲取各位朋友的知识见解。
    mybatis中根据日期模糊查询
    <![CDATA[文本内容]]>
    mybatis中sql标签和include标签
    Redis 安装
    Redis 简介
    从尾到头打印链表
    替换空格
  • 原文地址:https://www.cnblogs.com/CCTVCHCH/p/15870708.html
Copyright © 2020-2023  润新知