跳转至
#java  #java安全  #反序列化 
本文阅读量 

反射篇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");

回到页面顶部