您当前的位置: 首页 > 

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

杨林伟 发布时间:2019-10-28 14:41:49 ,浏览量:3

代码已上传至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)

注意抛出的异常: 在这里插入图片描述

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

总结

在这里插入图片描述

关注
打赏
1688896170
查看更多评论

杨林伟

暂无认证

  • 3浏览

    0关注

    3183博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文
立即登录/注册

微信扫码登录

0.3587s