反射技术
反射技术一般用来作框架使用。框架一般都是都是通过读取配置文件来运行指定类文件。
反射就是加载类,并解剖类的各个组成部分。
Class常用method(省略参数列表):
getConstructor()、getMethod()、getField()
getDeclaredConstructor()、getDeclareMethod()、getDeclareField()
区别:
没有declared的只能获取类中的public的声明部分,使用declared能获得private的声明部分。
反射类的Constructor示例:
package com.summer.day1;
public class Person {
private int age=10;
private String name= "aaa";
public Person() {
super();
System.out.println(age+name);
}
public Person(int age, String name) {
super();
this.age = age;
this.name = name;
System.out.println(age+name);
}
private Person(String name) {
super();
this.name = name;
System.out.println(age+name);
};
public void eat(String food){
System.out.println(food);
}
public static String run(String run){
System.out.println(run);
return run+" faster";
}
public static void main(String[] args){
System.out.println("main");
}
}
package com.summer.day1;
import java.lang.reflect.Constructor;
import org.junit.Test;
public class Refelct {
@Test
public void test1() throws Exception{
Class clazz= Class.forName("com.summer.day1.Person");
Constructor constructor=clazz.getConstructor(null);
constructor.newInstance();
}
@Test
public void test2() throws Exception{
Class clazz= Class.forName("com.summer.day1.Person");
//如果使用getConstructor则由于private权限问题会在下面一句报错
Constructor constructor=clazz.getDeclaredConstructor(String.class);
//没有设置成true则在newInstance时报错
constructor.setAccessible(true);
constructor.newInstance("bbb");
}
@Test
public void test3() throws Exception{
Class clazz= Class.forName("com.summer.day1.Person");
//本质是test1,找到无参构造函数,然后newInstance
//算是test1的简写形式
clazz.newInstance();
}
}
反射类的Method示例:
package com.summer.day1;
import java.lang.reflect.Method;
import org.junit.Test;
public class MethodDemo {
@Test
public void test1() throws Exception{
Class clazz= Class.forName("com.summer.day1.Person");
//指明函数名和传递参数列表
Method method = clazz.getMethod("eat", String.class);
Person p=new Person();
//指明调用的对象和参数值
method.invoke(p, "apple");
}
@Test
public void test2() throws Exception{
Class clazz= Class.forName("com.summer.day1.Person");
Method method = clazz.getMethod("run", String.class);
//如果方法为静态的可以不需要指定调用的对象,用null
//方法的结果为invoke的返回结果
String ans=(String) method.invoke(null, "run");
System.out.println(ans);
}
@Test
/**
* 调用main方法需要注意main(String[] args)的参数传递
* 这是因为在jdk1.5前没有可变参数所引起的,没有可变参数前是invoke(Object,Object[]),
* 他会将值列表Object[]中的内容提取出来然后根据函数名和参数列表去找对应的method
* 因此method.invoke(null, new String[]{"aa","bb"});会被认为是去寻找main(String,String)
* 所以找不到,现实参数列表的个数错误
* @throws Exception
*/
public void test3() throws Exception{
Class clazz= Class.forName("com.summer.day1.Person");
Method method = clazz.getMethod("main", String[].class);
/*
* method.invoke(null, new String[]{"aa"});
*这个居然显示参数类型不匹配,只有一个值的数组居然不可以
*/
/*
* method.invoke(null, new String[]{"aa","bb"});
* 这个现实参数列表的个数错误
*/
/* method.invoke(null, (Object)new String[]{"aa","bb"});
* 这样将数组变为了类,invoke不需要去提取类中的内容,所以能通过
**/
method.invoke(null, new Object[]{new String[]{"aa","bb"}});
}
}
反射类的Field类似,主要方法get()和set()方法类似于Constructor的newInstance和Method的invoke方法。对于私有的field可以使用getDeclareField()得到,但是如果想get的话要先修改setAccessible(true)。字段如果不是static,则在get字段时需要指明是那个实力的field。