一、反射
反射被视为动态语言的关键,反射机制允许程序在执行期间借助于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实例。
每一个运行时类只加载一次。
原文地址:https://www.cnblogs.com/chen-ying/p/11074578.html