• 11.【Java核心.反射】反射的概念、使用示例、spring IOC中的运用


    反射

    1.反射的定义:

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

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

    优点

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

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

    缺点

    ​ 相比于直接调用反射有比较大的性能消耗

    ​ 内部暴露和安全隐患

    反射到底慢在哪里?

    1.调用了native方法

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

    2.反射的操作

    2.1基本操作

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

    // 获取类对象的四种方式
    Class<User> clazz1 = User.class;
    Class<?> clazz2 = Class.forName("com.fatsea.modeel.entity.User");
    Class<? extends User> clazz3 = new User().getClass();
    Class<?> clazz4 = Demo03.class.getClassLoader().loadClass("com.fatsea.modeel.entity.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,"hello");
        }
    

    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("fatsea","男"));
    
    
        }
    

    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());
            }
        }
    
  • 相关阅读:
    uni-app爬坑之旅_开发一个自己的app_day61_将clock页面信息存储到数据库
    uni-app爬坑之旅_开发一个自己的app_day59_实现早晚时钟切换
    uni-app爬坑之旅_开发一个自己的app_day57_实现区域变色功能
    uni-app爬坑之旅_开发一个自己的app_day55_实现不规则区域的点击判定
    uni-app爬坑之旅_开发一个自己的app_day54_时钟背景透明化
    uni-app爬坑之旅_开发一个自己的app_day53_写出clock页面
    uni-app爬坑之旅_开发一个自己的app_day51_对不规则区域的制作有了一些头绪
    uni-app爬坑之旅_开发一个自己的app_day49_钟表功能遇到一个难题
    uni-app爬坑之旅_开发一个自己的app_day48_生成计划功能的实现思路
    【申请经验】给希望攻读计算机科学研究生的外国学生的建议(翻译)
  • 原文地址:https://www.cnblogs.com/Nick-Hu/p/14542268.html
Copyright © 2020-2023  润新知