1.什么是反射
通过类的全类名就能把这个类的所有方法和变量的信息(方法名,变量名,方法,修饰符,类型,方法参数等等所有信息)找出来。如果明确知道这个类里的某个方法名+参数个数 类型,还能通过传递参数来运行那个类里的那个方法,这就是反射。反射的具体方法不多说。这里只说三种获得类类型的方式:
- 通过类名.class获得,执行静态块、不执行动态构造块,动态构造块在newInstance的时候执行
- 通过对象名.getClass()获得 (需要获得实例对象),实例对象的时候执行静态块和动态构造块
- 通过Class.forName(“类全名”)获得,执行静态块、不执行动态构造块,动态构造块在newInstance的时候执行
2.反射的原理
3.反射使用时的技巧
⑴invoke方法可以传入强转后传object[]
public class Test {
public static void main(String[] args) throws Exception {
Dog dog = new Dog();
dog.setLength(123);
dog.setName("蔡丸子");
Object object = (Object) dog;
// 通过下面的方式也可以.
// Object object = JSONObject.parseObject("{\"length\":123,\"name\":\"黑豆\"}",Dog.class); object.class是不行的.
Man man = new Man();
man.setAge(23);
man.setName("蔡彬");
Object object1 = (Object) man;
// 这里的objects里面必须是强转后的,否则调用方法的时候报类型不匹配.
Object[] objects = new Object[]{
object, object1
};
Class<?>[] a = new Class<?>[]{
Class.forName("testswitch.Dog"),
Class.forName("testswitch.Man")
};
Class<?> clazz = Class.forName("testswitch.Test");
Method method = clazz.getDeclaredMethod("test",a);
method.invoke(clazz.newInstance(),objects);
}
public void test(Dog dog, Man man) {
System.out.println(dog.getLength());
System.out.println(man.getAge());
}
public void test1() {
System.out.println("123");
}
}
输出:
123
23
⑵调用无参方法传null或者空集合都可以
public static void main(String[] args) throws Exception {
Object[] objects = new Object[]{
};
Class<?>[] a = new Class<?>[]{
};
Class<?> clazz = Class.forName("testswitch.Test");
// a是null也可以.
Method method = clazz.getDeclaredMethod("test1", a);
// objects是null也可以.
method.invoke(clazz.newInstance(), objects);
}
public void test1() {
System.out.println("123");
}
输出:
123
⑶反射中包含有可变的参数.
public class TestInvoke {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("testswitch.TestInvoke");
Method method = clazz.getDeclaredMethod("getYear", String[].class);
String[] in = new String[]{"123"};
// 引用类型我们需要把这个数组实参先包装成一个Object对象或把实际参数作为一个Object一维数组的元素再传递.不传的话传一个new数组进去.
method.invoke(clazz.newInstance(), (Object) in);
method.invoke(clazz.newInstance(), new Object[]{in});
// 基本类型不需要.
Method method2 = clazz.getDeclaredMethod("getYear2", int[].class);
int[] in2 = new int[]{123};
method2.invoke(clazz.newInstance(),in2);
}
public int getYear(String... in) {
System.out.println("123");
return 666;
}
public int getYear2(int... in) {
System.out.println("222");
return 888;
}
}
输出:
123
123
222
⑷反射方法中有集合
public class TestInvoke {
public static void main(String[] args) throws Exception {
Man man = new Man();
man.setName("蔡彬");
man.setAge(23);
Dog dog1 = new Dog();
dog1.setName("狗1");
Dog dog2 = new Dog();
dog2.setName("狗2");
Class<?> c = Class.forName("testswitch.TestInvoke");
Class<?> p1 = Class.forName("testswitch.Man");
// 这里直接是List的全限定名.
Class<?> p2 = Class.forName("java.util.List");
Class<?>[] array = new Class[]{p1, p2};
Method method = c.getDeclaredMethod("getYear", array);
List<Dog> dogs = new ArrayList<>();
dogs.add(dog1);
dogs.add(dog2);
Object[] manobjects = new Object[]{man, dogs};
method.invoke(c.newInstance(), manobjects);
}
public void getYear(Man man, List<Dog> dogs) {
for (int i = 0; i < dogs.size(); i++) {
System.out.println(dogs.get(i).getName());
}
}
}
⑸反射获得基本类型数组,基本类型取不到
Class intArray = Class.forName("[I");
Class stringArrayClass = Class.forName("[Ljava.lang.String;");
我们不知道的可以这样打出来:
long[] longs = new long[]{
1,2,3
};
// [[J@555590] 就是[J
System.out.println(Arrays.asList(longs));
⑹反射获取对象数组
Class stringArrayClass = Array.newInstance(Class.forName("testswitch.Dog"), 0).getClass();
Class stringArrayClass = Class.forName("[L" + "testswitch.Dog" + ";");