0
点赞
收藏
分享

微信扫一扫

设计模式系列教程(01) - 反射机制(一)

探头的新芽 2022-03-23 阅读 13


代码已上传至Github,有兴趣的同学可以下载来看看:https://github.com/ylw-github/Java-DesignMode

1. 什么是Java反射机制

就是正在运行,动态获取这个类的所有信息。

2. 反射机制的作用

  1. 反编译:.class–>.java

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

3. 反射机制的应用场景

  • Jdbc 加载驱动

  • Spring IOC

  • 框架

4. 反射机制获取类的三种方式

第一种方式:使用Class.forName的方式

Class class1 = Class.forName("Employee")

第二种方式:java中每个类型都有class 属性.

Class class2 = Employee.class;

第三种方式:java语言中任何一个java对象都有getClass 方法.

Employee e = new Employee();
Class class3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)

注意抛出的异常:

设计模式系列教程(01) - 反射机制(一)_反射机制

5. 反射创建对象的方式

方式一:创建此Class 对象所表示的类的一个新实例 调用了Employee的无参数构造方法.

Class<?> forName = Class.forName("com.ylw.reflect.Employee");
Object newInstance = forName.newInstance();

方式二:实例化有参构造函数

Class<?> forName1 = Class.forName("com.ylw.reflect.Employee");
Constructor<?> constructor = forName1.getConstructor(String.class, String.class);
Employee newInstance1 = (Employee) constructor.newInstance("张三", "男");

注意抛出的异常:

设计模式系列教程(01) - 反射机制(一)_反射机制_02

6. 反射创建API

方法名称

作用

getDeclaredMethods []

获取该类的所有方法

getReturnType()

获取该类的返回值

getParameterTypes()

获取传入参数

getDeclaredFields()

获取该类的所有字段

setAccessible

允许访问私有成员

7. 使用反射为类私有属性赋值

Employee类:

package com.ylw.reflect;

public class Employee {

private String name;
private String sex;

public Employee() {
}

public Employee(String name, String sex) {
this.name = name;
this.sex = sex;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getSex() {
return sex;
}

public void setSex(String sex) {
this.sex = sex;
}

@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", sex='" + sex + '\'' +
'}';
}
}

测试方法:

public static void setValue() throws ClassNotFoundException,
IllegalAccessException, InstantiationException,
NoSuchFieldException {
Class<?> classUser = Class.forName("com.ylw.reflect.Employee");

//Test1: 获取到当前的所有属性
Field[] fields = classUser.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
}

//Test2: 获取当前所有的方法
Method[] declaredMethods = classUser.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method.getName());
}

//1. 为Employee对象私有属性赋值
Employee employee = (Employee) classUser.newInstance();
Field nameField = classUser.getDeclaredField("name");
// 标记为true 允许反射赋值
nameField.setAccessible(true);
nameField.set(employee, "张三");

Field sexField = classUser.getDeclaredField("sex");
// 标记为true 允许反射赋值
sexField.setAccessible(true);
sexField.set(employee, "男");
System.out.println("使用反射机制给Employee赋值为:"+ employee.toString());

}

运行结果:

设计模式系列教程(01) - 反射机制(一)_赋值_03

8. JDBC反射加载驱动

// 加载驱动类
Class.forName("com.mysql.jdbc.Driver");

// 通过DriverManager获取数据库连接
String url = "jdbc:mysql://192.168.1.150/test";
String user = "teamtalk";
String password = "123456";
Connection connection = (Connection) DriverManager.getConnection(
url, user, password);

PreparedStatement statement = (PreparedStatement) connection.prepareStatement(
"insert persion (name, age) value (?, ?)");
statement.setString(1, "hdu");
statement.setInt(2, 21);
statement.executeUpdate();

ResultSet resultSet = statement.executeQuery("select * from persion");
// 操作ResultSet结果集
while (resultSet.next()) {
// 第一种获取字段方式
System.out.println(resultSet.getString(1) + " " +
resultSet.getString(2) + " " + resultSet.getString(3));
}

// 关闭数据库连接
resultSet.close();
statement.close();
connection.close();

对于​​Class.forName("com.mysql.jdbc.Driver")​​​涉及到了JVM类加载的机制,可以参考文章:《设计模式系列教程(02) - 反射机制(二)》一文。

9. 如何禁止使用反射机制初始化

方法:将构造函数为私有化!

PrivateEmployee类:

package com.ylw.reflect;

public class PrivateEmployee {
private String name;
private String sex;

private PrivateEmployee() {
}

private PrivateEmployee(String name, String sex) {
this.name = name;
this.sex = sex;
}
// getter setter...
}

例如:把上述的Employee构造函数设置为私有类,会抛异常:

private static void testPrivateClazz() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class<?> classUser = Class.forName("com.ylw.reflect.PrivateEmployee");

//Test1: 获取到当前的所有属性
Field[] fields = classUser.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
}

//Test2: 获取当前所有的方法
Method[] declaredMethods = classUser.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method.getName());
}

//1. 为Employee对象私有属性赋值
PrivateEmployee employee = (PrivateEmployee) classUser.newInstance();
Field nameField = classUser.getDeclaredField("name");
// 标记为true 允许反射赋值
nameField.setAccessible(true);
nameField.set(employee, "张三");

Field sexField = classUser.getDeclaredField("sex");
// 标记为true 允许反射赋值
sexField.setAccessible(true);
sexField.set(employee, "男");
System.out.println("使用反射机制给Employee赋值为:"+ employee.toString());

}

抛异常:

设计模式系列教程(01) - 反射机制(一)_赋值_04

name
sex
toString
getName
setName
setSex
Exception in thread "main" getSex
java.lang.IllegalAccessException: Class com.ylw.reflect.RefelectDemo can not access a member of class com.ylw.reflect.PrivateEmployee with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.Class.newInstance(Class.java:436)
at com.ylw.reflect.RefelectDemo.testPrivateClazz(RefelectDemo.java:92)
at com.ylw.reflect.RefelectDemo.main(RefelectDemo.java:12)

Process finished with exit code 1

总结

设计模式系列教程(01) - 反射机制(一)_反射机制_05



举报

相关推荐

0 条评论