使用反射的例子
Contact me
- Blog -> https://cugtyt.github.io/blog/index
- Email -> cugtyt@qq.com
- GitHub -> Cugtyt@GitHub
我们一般实例化一个对象是这样做的:
Test t = new Test();
但是你有没有想过如果我们不知道类的具体名字?听起来有点不能理解,不知道类怎么实例化。因为代码是一直变化的,比如我们要操作一个轮子库里的对象,我们可能有Gear1, Gear2 …,可能随时有新的Gear被加进来,我们怎么方便的实例化呢?
一个直接的做法是,用字符串判断:
object getGear(String gearClassName) {
if ("Gear1".equals(gearClassName)) {
return new Gear1();
} else ...
}
但是如果很庞大,这个就维护很麻烦。甚至有人会想到把所有的类都实例化好放在一个数组或是什么结构里,利用数组来读取,这样最致命的一个问题是如果类多,内存会不够用。
这个时候我们看下反射是怎么做的,注意这里使用的是Java 10:
public class Main {
public static void main(String[] args) {
try {
Object test = Class.forName("Test").getDeclaredConstructor().newInstance();
// System.out.println(((Test) test).name);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Class的forName可以传入字符串,我们可以轻松的更改需要实例化的类名,你会得到一个Class<?>里面有一系列方法,获取构造函数可以用getDeclaredConstructor,这里获取的是方法,你可以用newInstance来实例化这个类。
当然你也可以获取类的所有方法,获取类的所有字段啥的。
试想这样一个情况,用户更新了代码,但是没有更新库,新代码要优先调用新的库里的类,那么如果就可以使用反射。反射可以让我们先尝试实例化新类,如果不行,捕获异常,我们可以用旧类替换,这样就提高了兼容性和稳定性。
发挥下想象它可以用来做什么,比如我们可以用它来做CODE Review,获取程序员写的代码,然后检查变量名和方法名是否符合规范,或是其他要求,重要的是我们的确不需要事先知道程序员写的类名是啥,要不然我们一个一个实例化,一个一个手动检查是非常低效的。
可见反射是比较强大的,如果随意使用修改了类的东西,可能会出现意想不到的情况,使用前需要考虑。