本文阅读量
反射篇2#
内部类与反射调用#
在java中要通过forname()
获取内部类,需要用到$符号,一个简单的示例如下
package top.longlone;
import java.lang.reflect.Constructor;
public class Hello {
class InnerClass {
public void print() {
System.out.println("here is InnerClass");
}
public InnerClass() {
}
}
public static void main(String[] args) throws Exception {
Class<?> innerClass = Class.forName("top.longlone.Hello$InnerClass");
Constructor<?> constructor = innerClass.getConstructor(Hello.class);
Object o = constructor.newInstance(Hello.class.newInstance());
System.out.println(o);
}
}
newInstance之痛#
有时候我们调用newInstance()
总是不成功,原因可能有如下2个:
- 类没有无参构造方法
- 构造方法是私有的
一个常见的例子就是java.lang.Runtime
,比如
Class clazz = Class.forName("java.lang.Runtime");
clazz.getMethod("exec", String.class).invoke(clazz.newInstance(), "id");
这时候会产生报错,因为
Runtime
的类构造方法是私有的,这里涉及到一个设计模式: 单例模式
单例模式是为了确保访问对象的唯一性,只需要实例化一次,之后不需要或不希望其再实例化,常见用于数据库连接(只连接一次数据库,而不是每次都连接)。
使用单例模式的类一般会提供一个getXXX()
的方法来获取唯一的实例,在java.lang.Runtime
中这个方法是getRuntime()
所以上述的代码我们应该改为
Class clazz = Class.forName("java.lang.Runtime");
clazz.getMethod("exec", String.class).invoke(clazz.getMethod("getRuntime").invoke(clazz), "calc.exe");
getMethod与函数重载#
getMethod的作用是通过反射获取一个类的某个特定的公有方法。而Java中支持方法重载,我们不能仅通过函数名来确定一个函数。所以,在调用getMethod的时候,我们需要传入需要获取的函数的参数类型列表。
以Runtime.exec为例,这个方法有6个重载
所以我们如果要拿到第一个重载,可以通过
clazz.getMethod("exec", String.class)
如果我们要拿到第二个重载,可以通过
clazz.getMethod("exec", String[].class);
通过反射调用Runtime.exec#
示例代码如下
Class clazz = Class.forName("java.lang.Runtime");
Method execMethod = clazz.getMethod("exec", String.class);
Method getRuntimeMethod = clazz.getMethod("getRuntime");
Object runtime = getRuntimeMethod.invoke(clazz);
execMethod.invoke(runtime, "calc.exe");