没有无参构造方法怎么实例化

如果一个类没有无参构造方法,也没有类似单例模式里的静态方法,我们怎样通过反射实例化该类呢?

这就需要使用到getConstructor这个方法了,先反射获取构造方法,然后调用newInstance获取实例化对象,传入构造函数所需要的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package org.javasec.FirstReflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

public class TestPro {
static void test() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
Class<?> clazz = Class.forName("java.lang.ProcessBuilder");
Method start = clazz.getMethod("start");
Constructor<?> ctor = clazz.getConstructor(List.class);
start.invoke(ctor.newInstance(Arrays.asList("calc")));
}
}

除此之外,还能使用强制类型转换,把实例化出来的ProcessBuilder当成一个整体,调用其start方法,而不是反射获取start方法了

1
2
3
4
5
6
public class TestPro {
static void test() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
Class<?> clazz = Class.forName("java.lang.ProcessBuilder");
((ProcessBuilder) clazz.getConstructor(List.class).newInstance(Arrays.asList("calc"))).start();
}
}

怎么调用可变长参数型的构造方法

可变长参数

对于可变长参数,Java其实在编译的时候会编译成一个数组,也就是说,下面两种写法在底层上是等价的

1
2
public void hello(String[] tests);
public void hello(String...tests);

因此对于一个hello(String...tests)函数,我们传参时,直接传入数组就能直接接收参数

回到问题,在反射中,我们怎么调用构造方法接收的参数是可变长参数的情况呢?同理,当成数组调用就行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package org.javasec.FirstReflect;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class TestPro {
static void test() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
Class<?> clazz = Class.forName("java.lang.ProcessBuilder");
((ProcessBuilder) clazz.getConstructor(String[].class).newInstance(new String[][]{{"calc"}})).start();
}
}

或者全部反射获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package org.javasec.FirstReflect;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class TestPro {
static void test() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {
Class<?> clazz = Class.forName("java.lang.ProcessBuilder");
clazz.getMethod("start").invoke(clazz.getConstructor(String[].class).newInstance(new String[][]{{"calc"}}));
}
}

怎么调用私有构造方法

调用getDeclaredConstructor即可,注意修改它的作用域setAccessible

1
2
3
4
Class clazz = Class.forName("java.lang.Runtime");
Constructor m = clazz.getDeclaredConstructor();
m.setAccessible(true);
clazz.getMethod("exec", String.class).invoke(m.newInstance(), "calc.exe");