反射机制学习记录

一、反射

反射被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并且直接操作任意对象的内部属性及方法。

二、Java反射机制提供的功能

在运行时判断任意一个对象所属的类;

在运行时构造任意一个类的对象;

在运行时判断任意一个类具有的成员变量和方法;

在运行时调用任意一个对象的成员变量和方法;

生成动态代理。

三、反射相关的API

java.lang.Class 代表一个类

java.lang.reflect.Method 代表类的方法

java.lang.reflect.Field 代表类的成员变量

java.lang.reflect.Constructor 代表类的构造方法

……

四、简单示例

public class Person {
    private String name;
    private int age;

    public Person() {
    }

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

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    public void show(){
        System.out.println("我是一个人");
    }

    public void display(String nation){
        System.out.println("我的国籍是"+nation);
    }

    @Override
    public String toString() {
        return "Person[name="+name+",age="+age;
    }
}



import org.junit.jupiter.api.Test;
import java.lang.reflect.Field;

public class TestReflection {

    //在有反射以前创建一个类的对象,并且调用其中的方法和属性
    @Test
    public void test1(){
        Person person=new Person();
        person.setAge(10);
        person.setName("小明");
        System.out.println(person);
        person.show();
        person.display("中国");
    }

    //通过反射以前创建一个类的对象,并且调用其中的结构
    @Test
    public void test2() throws IllegalAccessException, InstantiationException, NoSuchFieldException {
        Class<Person> clazz=Person.class;
        //创建clazz对应的运行时类Person类的对象
        Person person=clazz.newInstance();
        System.out.println(person);
        Field f1=clazz.getField("name");
        f1.set(person,"韩梅梅");
        System.out.println(person);
    }
}

可能运行test2()的时候回抛出如下异常:

没有“name”这个属性存在。出现这个异常的原因可能是对应字段不存在,或者对应的属性设置为私有,而私有的属性,反射也是无法获取的,改为public就可以。

修改以后的现象就是:

这就是通过反射调用运行时类的指定属性,可以调用公有也可以调用私有的属性,以及调用指定的方法:

//调用公有的属性
Field f1=clazz.getField("name");
f1.set(person,
"韩梅梅"); System.out.println(person); //调用私有的属性,getDeclaredField调用声明过的属性, // setAccessible设置访问权限 Field f2=clazz.getDeclaredField("age"); f2.setAccessible(true); f2.set(person,20); System.out.println(person);
//通过反射调用运行时类的指定方法
Method method1=clazz.getMethod("show");
method1.invoke(person);
Method method2=clazz.getMethod("display", String.class);//加上方法参数类型
method2.invoke(person,"中国中国");

1、Class类

首先了解Class类,它是反射的源头,

所有类都从Object类中继承了getClass()方法,它会返回一个Class类,即某个特定对象的运行时类。

产生对象的方式通常有两种:

正常方式:引入需要的“包类”名称——>通过new实例化——>取得实例化对象

反射方式:实例化对象——>getclass()方法——>得到完整的“包类”名称

简而言之:反射,即通过对象反射求出类的名称,从包类实例化,再反过来,再从实例获得运行时类,再由运行时类找倒其中的结构。某个对象对着镜子可以得到自己的属性、方法、构造器以及实现的接口等等信息。

Class本身就是一个类,Class对象只能由系统创建,一个类在JVM中只会有一个Class实例,一个Class对象对应的是已经加载到JVM的一个.class文件,每个类的实例都会记得自己由哪一个Class实例生成,所以通过Class可以得到一个类的完整结构。

 @Test
 public void test3(){
        Person person=new Person();
        //通过运行时类对象的getClass(),返回其运行时类
        Class clazz=person.getClass();
        System.out.println(clazz);
 }

输出结果:

我们创建一个类,通过编译(javac.exe),生成对应的.class文件,

之后加载(java.exe,通过JVM的类加载器来完成)此.class文件,

此.class文件加载到内存以后,就是一个运行时类,存放在缓存区,那么这个运行时类本身就是一个Class实例。

每一个运行时类只加载一次。

猜你喜欢

转载自www.cnblogs.com/chen-ying/p/11074578.html