Java-反射

一、反射

类字节码文件是在硬盘上存储的,是一个个的.class文件。我们在new一个对象时,JVM会先把字节码文件的信息读出来放到内存中,第二次用时,就不用再加载了,而是直接使用之前缓存的这个字节码信息。

字节码的信息包括:类名、声明的方法、声明的字段等信息。在Java中“万物皆对象”,这些信息当然也需要封装一个对象,这就是Class类、Method类、Field类。

通过Class类、Method类、Field类等等类可以得到这个类型的一些信息,甚至可以不用new关键字就创建一个实例,可以执行一个对象中的方法,设置或获取字段的值,这就是反射技术。

1. 获取Class对象的三种方式

Java中有一个Class类用于代表某一个类的字节码。
Java提供了三种方式获取类的字节码

/**
     * 加载类的字节码的3种方式
     * @throws Exception
     * */
    public void test1() throws Exception {
        // 方式一
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        // 方式二
        Class clazz2 = Person.class;
        // 方式三
        Person p1 = new Person();
        Class clazz3 = p1.getClass();
    }

2. 通过Class类获取类型的一些信息

  1. getName(): 类的名称(全名,全限定名)
  2. getSimpleName(): 类的的简单名称(不带包名)
  3. getModifiers(): 类的的修饰符
  4. 创建对象
    无参数构造创建对象
    newInstance()
  5. 获取指定参数的构造器对象,并可以使用Constructor对象创建一个实例

    Constructor getConstructor(Class<?>… parameterTypes)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /**
    * 通过Class对象获取类的一些信息
    *
    * @throws Exception
    * */

    private static void test2() throws Exception {

    Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
    // 获取类的名称
    String name = clazz1.getName();
    System.out.println(name); // cn.itcast.gz.reflect.Person
    // 获取类的简单名称
    System.out.println(clazz1.getSimpleName()); // Person
    // 获取类的修饰符
    int modifiers = clazz1.getModifiers();
    System.out.println(modifiers);
    // 构建对象(默认调用无参数构造.)
    Object ins = clazz1.newInstance();
    Person p = (Person) ins;
    System.out.println(p); // cn.itcast.gz.reflect.Person@c17164
    // 获取指定参数的构造函数
    Constructor<?> con = clazz1.getConstructor(String.class, int.class); //getConstructor()方法返回的是指定形参的构造方法,传入的形参是 数据类型对应的class类
    // 使用Constructor创建对象.
    Object p1 = con.newInstance("jack", 28);
    System.out.println(((Person) p1).getName());
    }
  6. 通过Class类获取类型中的方法的信息


1.获取公共方法包括继承的父类的方法
getMethods()返回一个数组,元素类型是Method
2.获取指定参数的公共方法
getMethod(“setName”, String.class);
3.获得所有的方法,包括私有
Method[] getDeclaredMethods()
4.获得指定参数的方法,包括私有

    Method getDeclaredMethod(String name, Class<?>... parameterTypes)
    /**
     * 获取公有方法.
     * @throws Exception
     * */
    private static void test3() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        // 1.获取非私用方法(包括父类继承的方法)
        Method[] methods = clazz1.getMethods();
        System.out.println(methods.length);
        for (Method m : methods) {
            // System.out.println(m.getName());
            if ("eat".equals(m.getName())) {
                m.invoke(clazz1.newInstance(), null);
            }
        }

    }

/**
     * 获取指定方法签名的方法
     * 
     * @throws Exception
     * */
    private static void test4() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        // 获取指定名称的函数
        Method method1 = clazz1.getMethod("eat", null);
        method1.invoke(new Person(), null);
    }

/**
     * 获取指定方法名且有参数的方法
     * 
     * @throws Exception
     * */
    private static void test5() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        Method method = clazz1.getMethod("eat", String.class);
        method.invoke(new Person(), "包子");
    }

    /**
     * 获取指定方法名,参数列表为空的方法.
     * 
     * @throws Exception
     * */
        private static void test4() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        // 获取指定名称的函数
        Method method1 = clazz1.getMethod("eat", null);
         method1.invoke(new Person(), null);
     }

 /**
     * 反射静态方法
     * @throws Exception
     * */
     private static void test7() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        Method method = clazz1.getMethod("play", null);
        method.invoke(null, null);
    }

    /**
     * 访问私有方法 暴力反射
     * @throws Exception
     * */
    private static void test6() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        Method method = clazz1.getDeclaredMethod("movie", String.class);
        method.setAccessible(true);
        method.invoke(new Person(), "苍老师");
    }

4. 通过Class类获取类型中的字段的信息

1.获取公共字段
Field[] getFields()
2.获取指定参数的公共字段
Field getField(String name)
3.获取所有的字段
Field[] getDeclaredFields()
4.获取指定参数的字段,包括私用
Field getDeclaredField(String name)

/**
     * 获取公有的字段
     **/
    private static void test8() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        Field[] fields = clazz1.getFields();
        Person p = new Person();
        System.out.println(fields.length);
        for (Field f : fields) {
            System.out.println(f.getName());
            if ("name".equals(f.getName())) {
                System.out.println(f.getType().getName());
                f.set(p, "jack");
            }
        }
        System.out.println(p.getName());

     }


/**
     * 获取私有的字段
     * @throws Exception
     * */
    private static void test9() throws Exception {
        Class clazz1 = Class.forName("cn.itcast.gz.reflect.Person");
        Field field = clazz1.getDeclaredField("age");
        System.out.println(field.getName());
        field.setAccessible(true);
        Person p = new Person();
        field.set(p, 100);
        System.out.println(p.getAge());
    }

二、利用反射分析类

一个栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Scanner;

/*
* this program use reflection to print all feature of a class.
* include Constructors,Methods and Fields.
*/


public class ReflectText {
public static void main(String[] args){
String name;
if (args.length > 0){ //read class name from command line or user input
name = args[0];
}
else{
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the class name: (like java.util.Date)");
name = scanner.next();
}
try{ //print class name and superclass name.
Class c1 = Class.forName(name);
Class superc1 = c1.getSuperclass();
String modifiers = Modifier.toString(c1.getModifiers());
//getModifiers() 方法 返回修饰符的字节码,Modifier 类重写的 toString 方法返回其对应的字符串形式
if(modifiers.length() > 0){
System.out.print(modifiers+" ");
}
System.out.print("class "+name);
if (superc1 != null && superc1 != Object.class ){
System.out.print(" extends "+superc1.getName());
}
System.out.print("\n{\n");
printConstructors(c1);
System.out.println();
printMethods(c1);
System.out.println();
printFields(c1);
System.out.println("}");

}
catch(ClassNotFoundException e){
e.printStackTrace();
}
System.exit(0);
}
public static void printConstructors(Class c){
Constructor[] constructors = c.getDeclaredConstructors();
for (Constructor con :constructors){
String name = con.getName();
System.out.print(" ");
String modifiers = Modifier.toString(con.getModifiers());
if (modifiers.length() > 0){
System.out.print(modifiers+ " ");
}
System.out.print(name +"(");

Class[] paramTypes = con.getParameterTypes();
// getParameterrTypes() 方法返回 constructor 所代表的构造方法的形参类型,返回值是一个数组
for (int i = 0; i < paramTypes.length ;i++){
if (i > 0) System.out.print(",");
System.out.print(paramTypes[i].getName());
}
System.out.print(");");
}
}
public static void printMethods(Class c){
Method[] methods = c.getDeclaredMethods(); //getDeclaredMethods()方法返回这个类或接口的所有方法,但不包括继承的方法
// getMethod() 将返回所有共有方法(包括继承的方法)
for (Method m : methods){
Class retType = m.getReturnType();
String name = m.getName();
System.out.print(" ");
//print modifiers,return type and method name
String modifiers = Modifier.toString(m.getModifiers());
if (modifiers.length() > 0){
System.out.print(modifiers+" ");
}
System.out.print(retType.getName()+" "+name+"(");
//print parameter types
Class[] paramTypes = m.getParameterTypes();
for (int i = 0; i< paramTypes.length;i++){
if (i > 0) System.out.print(",");
System.out.print(paramTypes[i].getName());
}
System.out.println(");");
}
}
public static void printFields(Class c){
Field[] fields = c.getDeclaredFields();
// getFields()方法返回一个包含Field对象的数组,这些对象记录了这个类或者其超类的公有域
// getDeclaredFields()返回的数组包含这个类的全部域。
// 如果类中没有域,或者Class对象秒速的是基本类型或者数组类型,将返回一个长度为0的数组
for (Field f: fields){
Class type = f.getType();
String name = f.getName();
System.out.print(" ");
String modifiers =Modifier.toString(f.getModifiers());
if (modifiers.length() > 0) System.out.print(modifiers+" ");
System.out.println(type.getName()+" "+name+ ";");
}
}
}