闭关修炼(八)反射机制


反射

什么是反射机制?

反射机制就是正在运行(的程序中)动态获取类的所有信息。

反射机制的作用

  1. 反编译:.class -> .java。

  2. 通过反射机制访问对象属性,方法,构造方法等。

  3. 使用java反射机制可以不用new来初始化类。

  4. 类私有属性可以通过java反射机制赋值。

提高程序的扩展性,封装一些工具类,写框架都会用到反射机制。

通过java反射机制创建对象例子

初始化类使用new创建对象,现在用反射机制来创建对象。

使用默认无参构造函数创建对象

package ch8;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;

@Data
@AllArgsConstructor
@NoArgsConstructor
class User{
    private String username;
    private String password;
}
public class Test1 {
    @SneakyThrows
    public static void main(String[] args) {
        // forName中写类的完整路径,即包名+类名
        Class<?> aClass = Class.forName("ch8.User");
        // 使用默认无参构造函数创建对象
        User user = (User) aClass.newInstance();
        System.out.println(user);

    }
}

在这里插入图片描述

使用有参构造函数创建对象

package ch8;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;

import java.lang.reflect.Constructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
class User{
    private String username;
    private String password;
}
public class Test1 {
    @SneakyThrows
    public static void main(String[] args) {
        /*
        // forName中写类的完整路径,即包名+类名
        Class<?> aClass = Class.forName("ch8.User");
        // 使用默认无参构造函数创建对象
        User user = (User) aClass.newInstance();
        System.out.println(user);
        */
        // forName中写类的完整路径,即包名+类名
        Class<?> aClass = Class.forName("ch8.User");
        // 使用getConstructor获取有参构造函数
        // 参数传入有参构造函数的参数类型
        Constructor<?> constructor = aClass.getConstructor(String.class, String.class);
        // 创建对象
        User user2 = (User) constructor.newInstance("jack", "123");
        System.out.println(user2);
    }
}

怎么禁止反射机制?

把构造函数改成private修饰,但是反射还是能通过设置访问权限禁止禁止反射

spring中的运用场景

写标签的时候经常遇到类似下面的格式
<bean id=“user” class=“com.java.bean.User”>
class值写类的reference path,目的之一就是通过反射机制实例化对象

springIoc

jdbc中的运用场景

在加载jdbc驱动类的时候我们会写:
class.forNmae(“com.mysql.jdbc.Driver”)

使用反射机制访问方法和属性

访问属性

package ch8;


import java.lang.reflect.Field;

public class Test2 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 获取类的字节码文件
        Class<?> aClass = Class.forName("ch8.User");
        // 获取当前类的所有属性
        Field[] declaredFields = aClass.getDeclaredFields();
        // 遍历
        for (Field field : declaredFields) {
            // 打印名称
            System.out.println(field.getName());
        }

    }
}

在这里插入图片描述

访问方法

package ch8;


import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test2 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 获取类的字节码文件
        Class<?> aClass = Class.forName("ch8.User");
        // 获取类的所有方法
        Method[] declaredMethods = aClass.getDeclaredMethods();
        // 遍历输出
        for (Method m : declaredMethods){
            System.out.println(m.getName());
        }
    }
}

给私有属性赋值

package ch8;


import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
        // 获取类的字节码文件
        Class<?> aClass = Class.forName("ch8.User");
        // 实例化对象
        User user = (User) aClass.newInstance();
        // 获取属性
        Field username = aClass.getDeclaredField("username");
        // 设置权限,允许操作私有属性
        username.setAccessible(true);
        // 属性赋值,第一个参数是类的对象, 第二个参数是赋的值
        username.set(user, "likeghee");
        // 获取属性
        Field password = aClass.getDeclaredField("password");
        // 设置权限
        password.setAccessible(true);
        // 属性赋值
        password.set(user, "1234");
        // 打印
        System.out.println(user);
    }
}

乞丐版springIOC实现

什么是springIOC?

控制反转,将bean与bean之间的关系交给第三方容器进行管理,不用自己手动创建对象。

springioc过程

加载springxml配置文件
传入beanid获取bean对象

springioc创建对象

使用无参构造函数

实现思路

  1. 用dom4j解析xml
  2. 通过beanid查找对应的xml节点,获取class节点属性
  3. 使用java反射机制newInstance类
  4. 使用java的反射机制给类属性赋值

实现

新建一个Context.xml放到resources文件夹下,模拟spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans>
    <bean id="user1" class="myspringioc.User">
        <property name="username" value="ghee"/>
        <property name="password" value="123"/>
    </bean>
</beans>

新建ClassPathXmlApplicationContext类,实现它的getBean方法

package myspringioc;

import lombok.SneakyThrows;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.lang.reflect.Field;
import java.util.List;

public class ClassPathXmlApplicationContext {
    private static String PATH;
    private static String ID;
    private static String CLASS;
    private static String NAME;
    private static String VALUE;
    
    public void init() {
        ID = "id";
        CLASS = "class";
        NAME = "name";
        VALUE = "value";
    }


    // 构造函数
    public ClassPathXmlApplicationContext(String path) {
        PATH = path;
    }

    @SneakyThrows
    public Object getBean(String id) {
        init();

        /*
        1. 用dom4j解析xml
        2. 通过beanid查找对应的xml节点,获取class节点属性
        3. 使用java反射机制newInstance类
        4. 使用java的反射机制给类属性赋值
        */
        if (id.equals("")) {
            return null;
        }
        SAXReader saxReader = new SAXReader();
        // 读取resources下的配置文件
        Document read = saxReader.read(this.getClass().getClassLoader().getResource(PATH));
        // 遍历二级节点,查询beanid
        // 获取根节点
        Element rootElement = read.getRootElement();
        // 获取二级节点
        List<Element> elements = rootElement.elements();
        // 遍历查找
        for (Element e : elements) {
            // 获取id属性的值
            String beanId = e.attributeValue(ID);
            // 如果和传入的id相等,找到bean
            if (!beanId.equals(id)) {
                // 如果不相等就跳出本次循环
                continue;
            }
            // 找到了beanid
            // 获取class属性值,也就是包PTAH
            String  attClassPath = e.attributeValue(CLASS);
            // 初始化bean
            Class<?> aClass = Class.forName(attClassPath);

            Object classObj = aClass.newInstance();

            // 获取三级节点
            List<Element> propertyList = e.elements();
            for(Element property: propertyList){
                // 获取name属性的值
                String attNameValue = property.attributeValue(NAME);
                // 通过反射找到类中的属性
                Field declaredField = aClass.getDeclaredField(attNameValue);
                // 获取value属性的值
                String attValueValue = property.attributeValue(VALUE);
                // 设置访问权限
                declaredField.setAccessible(true);
                // 类属性赋值
                declaredField.set(classObj, attValueValue);
            }
            return classObj;
        }
        return null;
    }

}

测试代码

package myspringioc;


public class Test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("Context.xml");
        User user1 = (User) classPathXmlApplicationContext.getBean("user1");
        System.out.println(user1);
    }
}

乞丐版ioc实现成功了
在这里插入图片描述

使用方便,但是初始化对象效率很低。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值