深入理解Java反射技术及其应用

image-20240909151040278

什么是反射技术?

Java反射机制是一种强大的特性,它允许程序在运行时动态加载类并获取类或对象的属性和方法。其核心在于JVM通过获得class对象进行反编译,从而获取对象的各种信息。

反射机制的基本特点

  1. 动态性
    Java是一种先编译后运行的语言,程序中对象的类型在编译期确定。而反射机制使得在运行时可以动态创建对象和调用其属性,无需在编译期知晓具体运行的对象。

  2. 灵活性
    通过反射,程序可以在运行时动态获取类的成员方法、属性等信息,并对其灵活调用。这一特性使得可以编写更加通用和灵活的代码。

  3. 类加载
    类加载器负责将class文件读取到内存中,反射机制能够在加载类之后,利用class对象访问类的信息。

获取class对象的三种方式

// 1. 通过类名称直接获取
Class<UserEntity> userEntityClass = UserEntity.class;

// 2. 通过实例对象获取
UserEntity userEntity = new UserEntity();
Class<? extends UserEntity> aClass = userEntity.getClass();

// 3. 通过类的完整路径获取
Class<?> aClass1 = Class.forName("com.yk.entity.UserEntity");

反射技术的优缺点

优点:

  • 动态获取:允许在运行时获取类的各种信息,对Java这类编译语言来说,能够更加灵活地创建和使用对象。
  • 无缝集成:能够实现组件之间的动态装配,无需源代码的连接,更容易实现面向对象编程。

缺点:

  • 性能消耗:反射的操作相较于直接调用会消耗更多的系统资源,因此在不需要动态创建对象的情况下最好避免使用反射。
  • 安全隐患:反射机制可以忽略权限检查,可能破坏封装性,导致安全问题。

反射机制的应用场景

  1. JDBC中使用Class.forName("com.yk.jdbc.Driver")
  2. Spring框架底层基于反射初始化对象
  3. 动态代理模式的实现

反射技术示例

1. 使用反射初始化对象

Class<?> aClass = Class.forName("com.yk.entity.UserEntity");
// 创建对象,默认调用无参构造方法
UserEntity userEntity = (UserEntity) aClass.newInstance();
System.out.println(userEntity);

// 使用有参构造方法创建对象
Constructor<?> constructor = aClass.getConstructor(String.class, Integer.class);
UserEntity user = (UserEntity) constructor.newInstance("yk", 21);
System.out.println(user);

2. 获取构造方法

Class<?> aClass = Class.forName("com.yk.entity.UserEntity");
Constructor<?>[] constructors = aClass.getConstructors();  // 获取公有构造方法
for (Constructor<?> co : constructors) {
    System.out.println(co);
}

System.out.println("=======");

Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors(); // 获取所有构造方法
for (Constructor<?> co : declaredConstructors) {
    System.out.println(co);
}

3. 获取成员属性

Field[] fields = aClass.getFields(); // 获取所有公有字段
Field[] declaredFields = aClass.getDeclaredFields(); // 获取所有字段

4. 调用方法

Method nameMethod = aClass.getMethod("setName", String.class);
Method sumMethod = aClass.getMethod("setSum", int.class);

nameMethod.invoke(document, "解忧杂货店");
sumMethod.invoke(document, 30);
System.out.println(document);

5. 模拟MyBatis实现代理

SQL执行器
public class SQLHandler {
    private static final String URL = "jdbc:mysql://127.0.0.1:3306/study?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC";
    private static final String USERNAME = "root";
    private static final String PASSWORD = "root";

    // 执行SQL
    public static <T> List<T> execute(String sql, Class<T> resultType) {
        try (Connection connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
             PreparedStatement preparedStatement = connection.prepareStatement(sql);
             ResultSet resultSet = preparedStatement.executeQuery()) {
             
            ResultSetMetaData setMetaData = resultSet.getMetaData();
            List<T> list = new ArrayList<>();
            while (resultSet.next()) {
                Object resultData = resultType.getDeclaredConstructor().newInstance();
                for (int i = 1; i <= setMetaData.getColumnCount(); i++) {
                    String labelName = setMetaData.getColumnLabel(i);
                    Field declaredField = resultType.getDeclaredField(labelName);
                    declaredField.setAccessible(true);

                    switch (setMetaData.getColumnType(i)) {
                        case Types.INTEGER:
                            declaredField.setInt(resultData, resultSet.getInt(labelName));
                            break;
                        case Types.DOUBLE:
                            declaredField.setDouble(resultData, resultSet.getDouble(labelName));
                            break;
                        default:
                            String value = resultSet.getString(labelName);
                            if ("true".equals(value) || "false".equals(value)) {
                                declaredField.setBoolean(resultData, Boolean.valueOf(value));
                            } else {
                                declaredField.set(resultData, value);
                            }
                    }
                }
                list.add((T) resultData);
            }
            return list;
        } catch (SQLException | InstantiationException | IllegalAccessException | NoSuchFieldException | NoSuchMethodException e) {
            e.printStackTrace();
            return Collections.emptyList();
        }
    }
}
配置SQL语句
sql = select id, city_name_pinyin as cityNamePinyin, city_name as

测试调用

public class Test {
    public static void main(String[] args) throws IOException {
        Properties properties = new Properties();
        InputStream inputStream = Test.class.getResourceAsStream("sql.properties");
        properties.load(inputStream);
        String sql = properties.getProperty("sql");
        System.out.println(sql);
        List<City> cities = SQLHandler.execute(sql, City.class);
//        System.out.println(cities.size());
        for (City c : cities) {
            System.out.println(c);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值