前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java反射学习——定义、操作、单例漏洞、IOC应用

Java反射学习——定义、操作、单例漏洞、IOC应用

作者头像
向着百万年薪努力的小赵
发布2022-12-02 09:34:48
2150
发布2022-12-02 09:34:48
举报
文章被收录于专栏:小赵的Java学习

1.反射的定义

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

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

简洁明了的介绍一下反射的优缺点:

优点 ​ 增加程序的灵活性,避免固有逻辑写死到程序中 ​ 代码相对简洁,可以提高程序的复用性

缺点 ​ 相比于直接调用,反射有比较大的性能消耗 ​ 内部暴露和安全隐患

反射到底慢在哪里?

1.调用了native方法 2.每次都会做安全检查 比较耗时

反射的使用场景:

​ 1.jdbc封装

​ 2.SpringIOC

​ 3.JdbcTemplate

​ 4.Mybatis

​ …

2.反射的操作

2.1基本操作

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

假设我们有一个实体类 User

代码语言:javascript
复制
	// 获取类对象的四种方式
	Class<User> class1 = User.class;
	Class<?> class2 = Class.forName("类路径名");
	Class<? extends User> class3 = new User().getClass();
	Class<?> class4 = Demo03.class.getClassLoader().loadClass("类路径名");
2.1.2.基本信息操作
代码语言:javascript
复制
System.out.println(clazz1.getModifiers()); // 获取类的修饰符(二进制的int值)
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);//获取注解信息

值得一提的是获取类修饰符这个方法的返回值是一个int类型的数据,其解析请看我的这一篇文章 Java反射机制——getModifiers()方法的返回值.

2.2字段的操作

新建一个User类

在这里插入图片描述
在这里插入图片描述

利用Field对类的字段进行操作

代码语言:javascript
复制
   /**
     * Field操作
     * @param args
     */
    public static void main(String[] args) throws Exception {
        Class<User> userClass = User.class;
        // 获取User对象
        User user = userClass.newInstance();
        // 获取类型中定义的字段 公有的字段以及父类中公有的字段
        //getFields()与getDeclaredFields()方法的区别
        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 类中的方法操作

还是那个User类

代码语言:javascript
复制
    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 构造器的操作

代码语言:javascript
复制
    /**
     * 构造器的操作
     * @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("小明","男"));


    }

3.单例的漏洞

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

代码语言:javascript
复制
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处理即可

代码语言:javascript
复制
    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());

    }

4.反射的应用 SpringIOC

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

代码语言:javascript
复制
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);
        }
代码语言:javascript
复制
// 加载配置问题  SAX
Document doc = this.doLoadDocument(inputSource, resource);
// 配置文件解析 BeanDefinition
return this.registerBeanDefinitions(doc, resource);
代码语言:javascript
复制
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();
            }

        }
    }
代码语言:javascript
复制
    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());
        }
    }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-08-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.反射的定义
  • 2.反射的操作
    • 2.1基本操作
      • 2.2字段的操作
        • 2.3 类中的方法操作
          • 2.4 构造器的操作
          • 3.单例的漏洞
          • 4.反射的应用 SpringIOC
          相关产品与服务
          容器服务
          腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档