Java基础学习-反射

77 阅读3分钟

这是我参与8月更文挑战的第25天,活动详情查看:8月更文挑战

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为反射机制。

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法。所以先要获取到每一个字节码文件对应的Class类型的对象。

作为jdk1.5后的新特性,反射这个知识还是要掌握的,以前自己也知道个大概,但是从来没有系统的学习过,所以这次准备记录下。

先看看反射需要用到的包:java.lang.reflect

看看这个包的说明: 提供类和接口,以获得关于类和对象的反射信息。在安全限制内,反射允许编程访问关于加载类的字段、方法和构造方法的信息,并允许使用反射字段、方法和构造方法对其底层对等项进行操作。

在利用反射操作中,我们无非使用Constructor< T>、Field、Method三个类比较多。在我们学习这三个类之前,我们要知道java中通过字节码获取Class的三种方法:

  • 类名.class,例如,System.class
  • 对象.getClass(),例如,new Date().getClass()
  • Class.forName(“类名”),例如,Class.forName(“java.util.Date”) 下面我们通过实例测试:

(1)创建Person类

package com.dsw.reflect;

public class Person {
    private String name;
    private String age;
    public Person(){

    }

    public Person(String name,String age){
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }

    public void printMsg(){
        System.out.println(this.name + "--" + this.age);
    }
}

编写测试类:

public class ReflectDemo {

/**
 * @param args
 */
public static void main(String[] args) {
    //通过类名.class获取字节码
    Class clazz1 = Person.class;

    //通过对象.getClass()获取字节码
    Person person = new Person();
    Class clazz2 = person.getClass();

    //通过Class.forName("类名");获取字节码
    try {
        Class clazz3 = Class.forName("com.dsw.reflect.Person");
        System.out.println("clazz1 == clazz2:" + (clazz1 == clazz2));
        System.out.println("clazz2 == clazz3:" + (clazz2 == clazz3));
        System.out.println("clazz1.equals(clazz2):" + clazz1.equals(clazz2));
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}
}

可以看到运行结果:运行结果:

clazz1 == clazz2:true
clazz2 == clazz3:true
clazz1.equals(clazz2):true

只有获取到字节码,我们才能获取到类的Field、Method等相关方法。

image.png 注意: Method中invoke(Object obj,Object…args)第一个参数为类的实例,第二个参数为相应函数中的参数,我想问,我调用的函数本来是一个多参数(参数个数不确定)的函数,应该怎么办?

可以这样调用:method.invoke(object, new Object[][]{new Object[]{obj1, obj2}}); 这样相当于object.method(obj1, obj2);

public static void main(String[] args) {
    //通过类名.class获取字节码
    Class<Person> clazz = Person.class;
    try {
        Object obj = clazz.newInstance();
        Method method = clazz.getMethod("printMethod", new Class[]{String.class});
        method.invoke(obj, new Object[]{method.getName()});
        //获取所有的公共声明的方法
        Method[] methods = clazz.getMethods();
        if(methods != null && methods.length >0){
            for(int i=0;i<methods.length;i++){
                Method methodSub = methods[i];
                System.out.println(methodSub.getName());
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

运行结果如下:

Method:printMethod
getName
setName
printMethod
getAge
setAge
printMsg
wait
wait
wait
equals
toString
hashCode
getClass
notify
notifyAll

反射方法

在 Java 反射框架中,针对方法的反射也提供了很多方法供我们使用。

image.png

反射的作用:

  • 在运行时,构造任意一个类的对象
  • 在运行时,判断任意一个类的完整结构,比如属性,方法,内部类,实现接口等
  • 在运行时,判断任意一个对象所属的类
  • 在运行时,调用任意一个对象的属性和方法
  • 在运行时,生成动态代理