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

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

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

1. 什么是Java反射机制

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

2. 反射机制的作用

  1. 反编译:.class–>.java
  2. 通过反射机制访问java对象的属性,方法,构造方法

3. 反射机制的应用场景

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)

注意抛出的异常:

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("张三", "男");

注意抛出的异常:

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());
   }

运行结果:

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());
    }

抛异常:

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

总结

目录
相关文章
|
26天前
|
设计模式 Java Kotlin
Kotlin教程笔记(56) - 改良设计模式 - 装饰者模式
Kotlin教程笔记(56) - 改良设计模式 - 装饰者模式
37 2
|
26天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
25 2
|
1月前
|
设计模式 Java Kotlin
Kotlin教程笔记(54) - 改良设计模式 - 迭代器模式
Kotlin教程笔记(54) - 改良设计模式 - 迭代器模式
43 2
|
1月前
|
设计模式 Java API
Kotlin教程笔记(50) - 改良设计模式 - 工厂模式
Kotlin教程笔记(50) - 改良设计模式 - 工厂模式
43 2
|
1月前
|
设计模式 算法 Kotlin
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
Kotlin教程笔记(53) - 改良设计模式 - 策略模式
45 1
|
1月前
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
37 1
|
1月前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
|
1月前
|
设计模式 Java Kotlin
Kotlin教程笔记(56) - 改良设计模式 - 装饰者模式
Kotlin教程笔记(56) - 改良设计模式 - 装饰者模式
|
1月前
|
设计模式 JavaScript Scala
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
26 0
|
1月前
|
设计模式 JavaScript Scala
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
39 0