反射1
反射看起来有点不走寻常路,甚至给人一种“吃饱了撑的”的感觉:两行代码就能实现的事情,非要写20行,也不见性能有多少提升。它实际上是Java代码灵活性的保证,也是诸如Spring等知名框架的底层原理之一。开发者在使用框架的时候已经用到了该机制,只是因为框架屏蔽了这些细节所以没有察觉到而已。
反射的意义
正常写Java代码时,当我们引用了一个Java对象,我们基本上已经知道了该对象的全部信息:先用import语句导入该对象所对应的类 -> new语句通过这个类创建一个对象 -> 通过引用对该对象进行处理。在这个过程中,对象的类信息、依赖关系、函数调用已经写死在代码里了,换言之,在编译期就已经确定了。
但有些时候,你会操作什么样的对象你自己也不清楚。比如Spring框架的编写者,他们不可能预测到使用这个框架的人会创建什么样的业务类,以及这些业务类中会有什么样的依赖关系;编写者也不可能用import语句去导入那个尚未被编写的业务类。但是我们在使用Spring框架的过程中,框架还是实现了对我们编写的各种类的创建和管理。
想象这样一个小需求:编写一个类管理器,用户只需要输入该管理器自己编写类的类名,管理器就能实现对该类的管理。如果不采用反射的话,至少我想不到其他方法实现这一需求。
搭建实验场地
在工程中实现这样几个类作为反射的操作对象,这些类统一放在user包中。
package com.sunhw.user;
public class Person implements Eater {
private String name;
private int age;
protected String protField;
public String pubField;
public static String sex = "gunship";
public void hello() {
System.out.println("Person Hello");
}
@Override
public void eat() {
System.out.println("Person eat now");
}
protected void protectMethod() {
System.out.println("this is a protect function");
}
private void privateMethod() {
System.out.println("this is a private function");
}
}
代码语言:java复制package com.sunhw.user;
public class Student extends Person implements FasterEater{
private String stuID;
public Student() {}
public Student(String stuID) {
this.stuID = stuID;
}
@Override
public void hello() {
System.out.println("Student Hello");
}
@Override
public void eatQuickly() {
System.out.println("finish eating in 15 mins");
}
public String getStuID() {
return stuID;
}
private void playGames() {
System.out.println("play games");
}
}
代码语言:java复制package com.sunhw.user;
public interface Eater {
void eat();
}
代码语言:java复制package com.sunhw.user;
public interface FasterEater extends Eater{
void eatQuickly();
}
实验用例中涉及到了尽可能多的情况:两个类有继承,各自实现了不通的接口,接口之间也有继承;类中三种访问权限都涉及,同时也涉及到了静态变量。我觉得这样可以更好地查看反射的机制。
而程序的入口,我们放在main包中,以和我们的实验对象user包中的类隔离。
代码语言:java复制package com.sunhw.main;
import com.sunhw.user.Person;
public class Main {
public static void main(String[] args) {
Person person = new Person();
}
}