接上篇:JDK5.0新特性 (一)
反射
- 应用在一些通用性比较强的代码中。
- 后面学到的框架,大多数都是使用反射来实现的。
- 在框架开发中,都是基于配置文件开发的。
在配置文件中配置了类,可以通过反射得到类中的所有内容,可以让类中的某个方法执行。
类中的所有内容:属性、无参构造方法、有参构造方法、普通方法。
反射的原理:
- 首先把文件保存到本地硬盘,生成.java文件
- 编译java文件,生成.class文件
- 使用jvm,把class文件通过类加载器加载到内存中
- 万事万物都是对象,class文件在内存中使用Class类表示
- 当使用反射的时候,首先需要获取到Class类,得到这个类之后,就可以得到class文件里面的所有内容,包含:属性 构造方法 普通方法。
属性通过一个类 Filed
构造方法通过一个类 Constructor
普通方法通过一个类 Method
反射操作类里面的属性
我们先创建一个类,以便后面的实验使用。
public class Person {
// 属性
private String name;
private String id;
// 没有参数的构造方法
public Person() {
}
// 有参数的构造方法
public Person(String name, String id) {
this.name = name;
this.id = id;
}
// 普通方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
使用反射操作 无参数的构造方法
- 获取class类
三种方式:Class clazz1 = Person.class; Class clazz2 = new Person().getClass(); Class clazz3 = Class.forName("com.veeja.test09.Person");
问题: 比如,要对一个类进行实例化,可以new,如果不使用new,该怎么获取?
@Test
private void test1() throws Exception {
// 得到class
Class c3 = Class.forName("com.veeja.test09.Person");
// 得到Person类的实例
Person p = (Person) c3.newInstance();
}
- 操作无参数的构造方法
代码:@Test public static void test1() throws Exception { // 得到class Class c3 = Class.forName("com.veeja.test09.Person"); // 得到Person类的实例 Person p = (Person) c3.newInstance(); // 设置值 p.setName("zhangsan"); // 获取值 String name = p.getName(); System.out.println(name); }
使用反射操作 有参数的构造方法
- 得到类;
- 得到构造方法;
- 通过构造方法设置值并创建实例
@Test
// 操作有参数的构造方法
public static void test2() throws Exception {
// 得到class
Class c1 = Class.forName("com.veeja.test09.Person");
// 使用有参数的构造方法
// c1.getConstructors();//获取所有的构造方法
// 传递的是有参数的构造方法里面的参数类型,类型使用class形式传递
Constructor cs = c1.getConstructor(String.class, String.class);
// 通过有参数的构造方法设置值
// 通过有参数的构造方法创建Person实例
Person p1 = (Person) cs.newInstance("lisi", "100");
System.out.println(p1.getId() + " " + p1.getName());
}
使用反射操作 类的属性
- 得到类。
- 得到属性。
- 设置属性。
@Test
public static void test3() {
try {
// 得到class
Class class1 = Class.forName("com.veeja.test09.Person");
// 得到Person类的实例
Person p = (Person) class1.newInstance();
// 得到name属性
// class1.getDeclaredFields();//得到所有的属性,用的很少
Field f = class1.getDeclaredField("name");
// 设置可以操作私有的属性
f.setAccessible(true);
// 设置name值
f.set(p, "zhangsan");// 相当于p.name="zhangsan";
System.out.println(f.get(p));// 相当于p.name
} catch (Exception e) {
e.printStackTrace();
}
}
使用反射操作 类的普通方法
- 得到类
- 得到普通方法,使用
getDeclaredMethod()方法,传递两个参数,第一个参数是方法的名称,第二个参数是通过方法设置的值的类型。 - 让方法来运行,使用
invoke()方法,传递两个参数,一个是类的实例,另一个是设置的值。执行了invoke()方法之后相当于执行了serName()方法,并且通过这个方法设置了一个值。 - 如果操作的是私有的方法,也需要设置可以执行的权限:
method.setAccessible(true); - 静态方法调用的方式是类名.方法名(),不需要类的实例,所以使用反射操作静态方法的时候,也是不需要类的实例的:
method.invoke(null, "zhangsan");
@Test
public static void test4() throws Exception {
// 操作setName()方法
// 得到class
Class c = Class.forName("com.veeja.test09.Person");
// 得到Person类的实例
Person p = (Person) c.newInstance();
// 得到普通的方法
// c.getDeclaredMethods();//得到所有的普通方法,用的很少
Method m = c.getDeclaredMethod("setName", String.class);
//如果操作的是私有的方法,也需要设置可以执行的权限
m.setAccessible(true);
// 让setName方法执行,执行设置值
m.invoke(p, "zhangsan");
System.out.println(p.getName());
}
end.