什么是反射技术?
Java反射机制是一种强大的特性,它允许程序在运行时动态加载类并获取类或对象的属性和方法。其核心在于JVM通过获得class对象进行反编译,从而获取对象的各种信息。
反射机制的基本特点
-
动态性
Java是一种先编译后运行的语言,程序中对象的类型在编译期确定。而反射机制使得在运行时可以动态创建对象和调用其属性,无需在编译期知晓具体运行的对象。 -
灵活性
通过反射,程序可以在运行时动态获取类的成员方法、属性等信息,并对其灵活调用。这一特性使得可以编写更加通用和灵活的代码。 -
类加载
类加载器负责将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这类编译语言来说,能够更加灵活地创建和使用对象。
- 无缝集成:能够实现组件之间的动态装配,无需源代码的连接,更容易实现面向对象编程。
缺点:
- 性能消耗:反射的操作相较于直接调用会消耗更多的系统资源,因此在不需要动态创建对象的情况下最好避免使用反射。
- 安全隐患:反射机制可以忽略权限检查,可能破坏封装性,导致安全问题。
反射机制的应用场景
- JDBC中使用
Class.forName("com.yk.jdbc.Driver")
- Spring框架底层基于反射初始化对象
- 动态代理模式的实现
反射技术示例
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);
}
}
}