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());
        }
    }
原文地址:https://www.cnblogs.com/Nick-Hu/p/14542268.html