反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。在计算机科学领域,反射是一类应用,它们能够自描述和自控制。这类应用通过某种机制来实现对自己行为的描述和检测,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性和方法。
它被视为准动态语言的关键性质。Java反射机制的核心就是允许在运行时通过Java Reflection APIs来取得已知名字的class类的相关信息,动态地生成此类,并调用其方法或修改其域(甚至是本身声明为private的域或方法)。
从名字来说,既然是反射,就肯定先有“正”。而“正”就是指,我们在使用一个类的时候,首先要知道这个类,通过这个类来创建实例化对象。那么“反”就是指,我们通过对象去找到它所属的类。
说到对象,它在运行时有两种类型。
即 对象调用编译时类型的属性和运行时类型的方法
举一个例子来理解:
Person p = new Student();
//Student类继承自Person类
Java程序状态分为编译和运行。编译时,JVM在栈里静态创建基本数据变量和引用,这里p这个引用就是编译时创建的,所以p的编译时类型就是Person。而该行代码运行时,JVM在堆里为p创建了一块内存,对应着new Student()这句代码,所以p的运行时类型是Student。
那么说回正题。
提到反射机制,首先我们要了解Class类。 当时初学Java的时候,只是有个大概的认识,对于Class类并没有在意,翻看了好几篇文章,整理一下现在的理解。
在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。
类加载一共有5步,加载,验证,准备,解析和初始化。其中加载阶段,除了将字节码加载到方法区,还生成了这个类的Java.lang.Class对象。(关于类加载另外单独做笔记)
Class类说白也是一个类,只不过是在类加载过程中由虚拟机生成的特殊的类。Java是面向对象编程的,几乎所有数据都是对象,所以知道自己是哪种类型的对象是很必要的,而Class类就可以代表一个类的类型信息,里面存储了对应类的几乎所有的信息,当然这些信息是未初始化的信息,比如所有的方法,所有的构造函数,所有的字段(成员属性)等等。能够实现它所代表的这个类的所有功能,包括创建这个类的实例,获得所有的构造函数,方法,字段值等等,可以说无所不能。
图源http://www.cnblogs.com/crazypebble/archive/2011/04/13/2014582.html
如图,获取Class对象的方法有很多种。
使用java的反射一般需要三步。
首先写个Person类
package com.fish.test;
public class Person {
private String name = "nicefish";
private int age = 20;
public Person() {
System.out.println("我是无参构造方法");
}
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;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age +"]";
}
private void privateMethod() {
System.out.println("我是私有方法");
}
}
然后是几个基本操作。
public class Reflect1 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, NoSuchFieldException {
//取得Class对象
Class<?> cls = Class.forName("com.fish.test.Person");
//反射实例化对象
Object obj = cls.newInstance();
System.out.println(obj.toString());
//获得构造方法
Constructor<?> cons = cls.getConstructor(String.class, int.class, String.class);
//获得get方法
Method m0 = cls.getDeclaredMethod("getName");
//获得name属性
Field nameField = cls.getDeclaredField("sex");
}}
Constructor<?> cons = cls.getConstructor(String.class, int.class);
起初有报错,原因是获得构造方法的时候参数个数没有对应起来。
修改后输入为
我是无参构造方法
Person [name=nicefish, age=20]
下面再分别测试几种操作。
package com.fish.test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class getMethod {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
//该方法是获取本类以及父类或者父接口中所有的公共方法(public修饰符修饰的)
Class<?> cls = Class.forName("com.fish.test.Person");
Method []methods = cls.getMethods();
for (Method method : methods) {
//System.out.println(method.getName() + ", ");
}
//该方法是获取本类中的所有方法,包括私有的(private、protected、默认以及public)的方法。
Method []methods2 = cls.getDeclaredMethods();
for(Method method2 : methods2) {
//System.out.println(method2.getName() + ", ");
}
//获得指定的方法
Method method = cls.getDeclaredMethod("setAge", int.class); // 第一个参数是方法名,第二个是方法的参数类型
System.out.println("method :" + method);
//执行某方法
Object obj = cls.newInstance();
method.invoke(obj, 30);//第一个参数是实例化后的对象,第二个参数是传入方法的参数
System.out.println(obj.toString());
}
}
Person [name=nicefish, age=30]
package com.fish.test;
import java.lang.reflect.Field;
public class getField {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Class<?> cls = Class.forName("com.fish.test.Person");
//获取成员变量/字段
//获取指定名字的Field
Field field1 = cls.getDeclaredField("name");
Field field2 = cls.getDeclaredField("age");
System.out.println("Field :" + field1.getName());
System.out.println("Field :" + field2.getName());
//输出:Field :name
Field :age
//获取字段的数组,私有也可以获取
Field []fields = cls.getDeclaredFields();
for(Field field : fields) {
System.out.println(field.getName() + ", ");
}
//输出:name,
age,
//获取指定对象的Field值
Person person = new Person("方木", 30);
//name字段是private,所以在传参更改值的时候要先使用setAccessible函数
//取消了Java的权限控制检查(注意不是改变方法或字段的访问权限),修改了其private成员变量的值。
field1.setAccessible(true);
Object obj1 = field1.get(person);
System.out.println("person对象的字段name的值是:" + obj1);
//输出: person对象的字段name的值是:方木
//设置指定对象的Field值
field2.setAccessible(true);
field2.set(person, 45);
System.out.println("设置person对象的字段age的值为:" + person.getAge());
//输出:设置person对象的字段age的值为:45
}
}
定义一个父类
package com.fish.test;
public class Father {
public Father() {
}
private String method1() {
return "this is father's private method";
}
}
定义一个子类
package com.fish.test;
public class Son extends Father{
public Son() {
}
private void method2(int age) {
System.out.println("Son's age is :" + age);
}
}
获取父类中定义的方法
package com.fish.test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class getSuperClass {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class cls = Class.forName("com.fish.test.Son");
//获取父类的Class
Class superClass = cls.getSuperclass();
System.out.println(superClass);
Method m1 = superClass.getDeclaredMethod("method1");
Object obj = superClass.newInstance();
//method1是私有方法,同样的处理
m1.setAccessible(true);
System.out.println(m1.invoke(obj));
//输出:class com.fish.test.Father
this is father's private method
}
}
https://www.cnblogs.com/jiaqingshareing/p/6024541.html
http://www.cnblogs.com/gulvzhe/archive/2012/01/27/2330001.html