反射机制是在程序运行时获取任何一个类的字节码的所有信息,包括修饰符、构造方法、字段、方法实现接口等信息,并且可以在程序运行时根据字节码信息创建类的实例对象,改变该对象的字段内容和调用任意一个方法。
获取一个已知的类的内部信息可以通过以下三个类获取:
Constructor类:提供关于类的单个构造方法的信息以及对它的访问权限。
Field类:提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。
Method类:提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。
Constructor类、Field类、Method类都是由JVM虚拟机在程序运行时候创建。要获得这些对象,需先获得对应的类对象。
Person类:
package com.reflect;
public class Person {
private String userName;
private int age;
public double money;
public Person(){
}
private Person(String name){
this.userName = name;
}
public Person(String name,int age){
this.userName = name;
this.age = age;
}
public String getName() {
return userName;
}
public void setName(String name) {
this.userName = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void show(){
System.out.println("show...");
}
public void show(String msg){
System.out.println("show..."+msg);
}
@Override
public String toString() {
return "Person [name=" + userName + ", age=" + age + "]";
}
}
以下通过反射的方式获得Person类的实例对象:
例1:通过反射创建Person对象。
public class ClassTest {
public static void main(String[] args) throws ClassNotFoundException {
Person p1 = new Person();
Person p2 = new Person();
// 可以獲取到內存中這份class,Class表示内存中的那份字节码文件
Class clazz1 = p1.getClass();
Class clazz2 = p2.getClass();
System.out.println(clazz1 == clazz2);//true
//
System.out.println(clazz1 == Person.class);//
//
Class clazz3 = Class.forName("com.reflect.Person");
System.out.println(clazz1 == clazz3);//new关键字方法创建和反射方法创建两者比较
}
}
输出结果:
true
true
true
true说明这三种方法获得的Person实例对象是一样的。
例2:获得Constructor类对象,进而创建Person的实例对象。
public class ConstructorTest {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.reflect.Person");
Constructor con = clazz.getConstructor();
Person person = (Person) con.newInstance();
person.setName("张三");
person.setAge(25);
System.out.println(person.toString());
System.out.println("------------");
Constructor[] cs = clazz.getDeclaredConstructors();//获得所有类型的构造方法
for(Constructor c : cs){
System.out.println(c);
}
System.out.println("------------");
Constructor[] cs2 = clazz.getConstructors();//获得public类型构造方法
for(Constructor c : cs2){
System.out.println(c);
}
System.out.println("------------");//获得指定的参数的构造方法,如果有定义无参构造方法,会同时返回
Constructor cs3 = clazz.getConstructor(String.class,int.class);
System.out.println(cs3);
}
}
Person [name=张三, age=25]
------------
public com.reflect.Person()
public com.reflect.Person(java.lang.String,int)
private com.reflect.Person(java.lang.String)
------------
public com.reflect.Person()
public com.reflect.Person(java.lang.String,int)
------------
public com.reflect.Person(java.lang.String,int)
通过Constructor类创建对应的对象只能通过newInstance方法获得
例3:获得Field类,修改Person实例对象的属性值。
public class FieldTest {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.reflect.Person");
Field age = clazz.getDeclaredField("age");
age.setAccessible(true);//private修饰的属性必须设为true表示反射的对象在使用时应该取消 Java 语言访问检查
Person p = new Person();
System.out.println("before:"+p.getAge());//0
age.set(p, 10);
System.out.println("after:"+p.getAge());//10
Field userName = clazz.getDeclaredField("userName");
userName.setAccessible(true);
userName.set(p, "张三");
System.out.println("name="+p.getName());
System.out.println(p.toString());
//拿所有的属性
System.out.println("--------");
Field[] fs = clazz.getDeclaredFields();
for(Field f : fs){
System.out.println(f);
}
//拿到public类型的属性
System.out.println("--------");
Field[] fields = clazz.getFields();
for(Field f:fields){
System.out.println(f);
}
}
}
输出结果:
before:0
after:10
name=张三
Person [name=张三, age=10]
--------
private java.lang.String com.reflect.Person.userName
private int com.reflect.Person.age
public double com.reflect.Person.money
--------
public double com.reflect.Person.money
例4:获得Method类,调用Person实例对象的方法。
public class MethodTest {
public static void main(String[] args) throws Exception {
Person p = new Person();
/*p.show();
p.show("11");*/
Class clazz = Class.forName("com.reflect.Person");
Method method1 = clazz.getMethod("show");
method1.invoke(p);
Method method2 = clazz.getMethod("show", String.class);
method2.invoke(p, "1513");
}
}
输出结果:
show...
show...1513
例5:利用反射读取配置文件调用对应方法
配置文件config.txt:
className=com.reflect.Person
method=show
public class Test {
public static void main(String[] args) throws Exception {
//IO流技术读取配置文件,获取对应类名和方法名
/*BufferedReader reader = new BufferedReader(new FileReader("config.txt"));
String line1 = reader.readLine();//className=com.reflect.Other
String className = line1.substring(line1.indexOf("=")+1);
String line2 = reader.readLine();
String method = line2.substring(line2.indexOf("=")+1);
System.out.println(className);
System.out.println(method);
reader.close();*/
Properties pro = new Properties();
pro.load(new FileInputStream("config.txt"));
String className = pro.getProperty("className");
String method = pro.getProperty("method");
//反射技术动态调用对应方法
Class clazz = Class.forName(className);
Method m = clazz.getDeclaredMethod(method);
m.invoke(clazz.newInstance());
}
}
输出结果:
show...