知识点

JAVA 之深入理解反射

2019-06-21  本文已影响146人  煮黑豆

1.  反射的概述

1.1. 什么是反射
每个.class文件被加载到内存后都是一个Class类的对象!例如Demo.class加载到内存后它是Class<Demo>类型的一个对象。

图片1.png
反射就是通过Class对象获取类型相关的信息。一个Class对象就表示一个.class文件,可以通过Class对象获取这个类的构造器、方法,以及成员变量等。
反射是Java的高级特性,在框架中大量被使用!我们必须要了解反射,不然无法学好JavaWeb相关的知识!
1.2. 反射相关类
与反射相关的类:与反射相关的类们,它们都不能new!!!

2. Class类

2.1 获取Class类的三种基本方式

1、String getName():获取类名称,包含包名;
2、String getSimpleName():获取类名称,不包含包名;
3、Class getSupperClass():获取父类的Class,例如:new Integer(100).getClass().getSupperClass()返回的是Class<Number>!但new Object().getSupperClass()返回的是null,因为Object没有父类;

  • 4、T newInstance():使用本类无参构造器来创建本类对象;

通过反射创建对象

public class Demo1 {
    @Test
    public void fun1() throws Exception {
        String className = "cn.***.***";//包路径名
        Class clazz = Class.forName(className); 
        User user = (User)clazz.newInstance();
        System.out.println(user);
    }
}

class User {
    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User [username=" + username + ", password=" + password + "]";
    }
}

3 Constructor

[它是Class的一个组成部门,所以需要先得到Class,再通过Class的方法得到Constructor]
Constructor表示一个类的构造器。即构造器的反射对象!

3.1. 获取Constructor对象
  获取Construcator对象需要使用Class对象,下面API来自Class类:

1、Constructor getConstructor(Class… parameterTypes):通过指定的参数类型获取公有构造器反射对象;
2、Constructor[] getConstructors():获取所有公有构造器对象;
3、Constructor getDeclaredConstructor(Class… parameterTypes):通过指定参数类型获取构造器反射对象。可以是私有构造器对象;
4、Constructor[] getDeclaredConstructors():获取所有构造器对象。包含私有构造器;

3.2. Construcator类常用方法

1、String getName():获取构造器名;
2、Class getDeclaringClass():获取构造器所属的类型;
3、Class[] getParameterTypes():获取构造器的所有参数的类型;
4、Class[] getExceptionTypes():获取构造器上声明的所有异常类型;
5、T newInstance(Object… initargs):通过构造器反射对象调用构造器。

4 Method(类的组成部分)

Class 类的反射对象
Constructor 构造器的反射对象
Method表示方法的反射对象
Field 成员的反射对象

4.1. 获取Method
获取Method需要通过Class对象,下面是Class类的API:

1、Method getMethod(String name, Class… parameterTypes):通过方法名和方法参数类型获取方法反射对象,包含父类中声明的公有方法,但不包含所有私有方法;
2、Method[] getMethods():获取所有公有方法,包含父类中的公有方法,但不包含任何私有方法;
3、Method getDeclaredMethod(String name, Class… parameterTypes):通过方法名和方法参数类型获取本类中声明的方法的反射对象,包含本类中的私有方法,但不包含父类中的任何方法;
4、Method[] getDeclaredMethods():获取本类中所有方法,包含本类中的私有方法,但不包含父类中的任何方法。

4.2 Method常用方法

1、String getName():获取方法名;
2、Class getDeclaringClass():获取方法所属的类型;
3、Class[] getParameterTypes():获取方法的所有参数的类型;
4、Class[] getExceptionTypes():获取方法上声明的所有异常类型;
5、Class getReturnType():获取方法的返回值类型;
6、Object invode(Object obj, Object… args):通过方法反射对象调用方法,如果当前方法是实例方法,那么当前对象就是obj,如果当前方法是static方法,那么可以给obj传递null。args表示是方法的参数;

5 Field

Field表示类的成员变量,可以是实例变量,也可以是静态变量。

5.1. 获取Field对象
获取Field对象需要使用Class对象,下面是Class类的API:

1、Field getField(String name):通过名字获取公有成员变量的反射对象,包含父类中声明的公有成员变量;
2、Field[] getFields():获取所有公有成员变量反射对象,包含父类中声明的公有成员变量;
3、Field getDeclaredField(String name):通过名字获取本类中某个成员变量,包含本类的private成员变量,但父类中声明的任何成员变量都不包含;
4、Field[] getDeclaredFields():获取本类中声明的所有成员变量,包含private成员变量,但不包含父类中声明的任何成员变量;

5.2 Field类的常用方法

1、String getName():获取成员变量名;
2、Class getDeclaringClass():获取成员变量的类型;
3、Class getType():获取当前成员变量的类型;
4、Object get(Object obj):获取obj对象的成员变量的值;
5、void set(Object obj, Object value):设置obj对象的成员变量值为value;

6  AccessibleObject**

AccessibleObject类是Constructor、Method、Field三个类的父类。AccessibleObject最为重要的方法如下:

1、boolean isAccessible():判断当前成员是否可访问;
2、void setAccessible(boolean flag):设置当前成员是否可访问。//[当设置该参数为true时,那么private的成员、方法、构造器就都可以操作了。]

当Constructor、Method、Field为私有时,如果我们想反射操作,那么就必须先调用反射对象的setAccessible(true)方法,然后才能操作。
User.java

public class User {
    private String username;
    private String password;

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User [username=" + username + ", password=" + password + "]";
    }
}

注意,User类的username和password成员变量为private的,这时再通过Field来反射操作这两个成员变量就必须先通过setAccessible(true)设置后才行。

public class Demo1 {
    @Test
    public void fun1() throws Exception {
        String className = "cn.itcast.User";
        Class clazz = Class.forName(className);
        User user = new User("zhangSan", "123");
        
        Field field1 = clazz.getDeclaredField("username");
        Field field2 = clazz.getDeclaredField("password");
//[因为username和password都是私有的成员变量,所以需要使用getDeclaredField()才能获取到。]     
        field1.setAccessible(true);
        field2.setAccessible(true);
//[设置成员变量是可以访问的,对于私有变量、方法、构造器都必须先调用这个方法后才能操作,不然会抛出异常。]      
        String username = (String)field1.get(user);
        String password = (String)field2.get(user);
        
        System.out.println(username + ", " + password);
        
        field1.set(user, "liSi");
        field2.set(user, "456");
        
        System.out.println(user);
    }
}
上一篇下一篇

猜你喜欢

热点阅读