反射(Reflection)能够在代码运行期间、对任意未知类或对象访问属性和调用方法
反射的思想是建立对类的引用、然后通过传入对象名、访问对象的属性或者调用方法,Java机制是对每一个被加载的类新建一个唯一的实例,然后将该实例和类联系在一起
Integer a = 1; Class cls 1 = a.getClass(); String b = "Hello"; Class cls2 = b.getClass();
xxx.class
Class cls1 = String.class;
Class cls3 = null; try { cls3 = Class.forName("java.lang.String"); } catch (ClassNotFoundException e) { e.printStackTrace(); }
普通实例化使用new
int[] ints = new int[1];
使用反射使用Class.newInstance()
实例化
String str = String.class.newInstance();
由于所有类都继承自Object类,在我们不知道某类的时候,将它new成Object类,而我们无需去探究它的内部究竟是什么、接着我们获取它的类用以建立反射,才用上文提到的方法xxx.getClass()
获取
属性在field域中,对一个类使用Class.getField(String name)
即可获取它的属性,下面的f即是到Person类属性name的反射,然后通过Field.get(String instanceName)
方法传入我们实例名称即可获取此实例的name属性
import java.lang.reflect.Field; public class Main { public static void main(String[] args) throws Exception{ Object obj = new Person("zhangsan"); Class cls = obj.getClass(); Field f = cls.getField("name"); Object value = f.get(obj); System.out.println(value); // zhangsan } } class Person{ public String name; public Person(String name){ this.name = name; } }
可以发现在访问实例的属性的过程中:自始至终都没有关注过实例的类名
建立好反射后,更改属性只需要使用set方法,传入实例名和修改后的值即可
对于建立private属性的反射:需要使用Class.getDeclaredField(String name)
并且设置Field.setAccessible(true)
import java.lang.reflect.Field; public class Main { public static void main(String[] args) throws Exception{ Person p = new Person("lisi"); System.out.println(p.getName()); // lisi Class cls = p.getClass(); Field f = cls.getDeclaredField("name"); f.setAccessible(true); f.set(p,"wangwu"); System.out.println(p.getName()); // wangwu } } class Person{ private String name; public Person(String name){ this.name = name; } public String getName() { return this.name; } }
属性存放在Field中,而方法存放在Method中,使用Class.getMethod(String name,Class valueType1,...,Class valueTypeN)
即可获取到方法的反射,多个传参就需要多次传入参数的属性
invoke赋值需要类型转换
拿到反射后,使用Method.invoke()
传入实例和参数即可调用
import java.lang.reflect.Method; public class Main{ public static void main(String[] args) throws Exception { String s = "Hello World!"; // substring传参是两个int,起始和终止字符的索引值 Method f = String.class.getMethod("substring", int.class, int.class); String t = (String) f.invoke(s,3,7); System.out.println(t); // lo W } }
由于是静态方法,那invoke无需传入参数,即传入null
import java.lang.reflect.Method; public class ReflectionUseStaticMethod { public static void main(String[] args) throws Exception { Method m = Integer.class.getMethod("parseInt", String.class); Integer n = (Integer) m.invoke(null,"12"); System.out.println(n); // 12 } }
之前提到可以用newInstance()
实例化,但是它只能调用该类的public无参数构造方法。如果构造方法带有参数,或者不是public,就无法直接通过Class.newInstance()来调用。那么就需要调用它的构造方法了。
newInstance返回的是Object对象,所以需要向下转型
import java.lang.reflect.Constructor; public class Main { public static void main(String[] args) throws Exception{ Constructor cs = Integer.class.getConstructor(int.class); Integer a = (Integer) cs.newInstance(123); System.out.println(a); // 123 } }
使用方法Class.getSuperclass()
能够获取父类
public class ReflectionGetFatherClass { public static void main(String[] args) throws Exception { Class cls = Integer.class; Class father = cls.getSuperclass(); System.out.println(father); // class java.lang.Number } }
使用方法Class.getInterfaces()
能够获取接口数组(接口也是类)
package LiaoxuefengTest; public class ReflectionGetInterfaces { public static void main(String[] args) throws Exception { Class cls = Integer.class; Class[] ifs = cls.getInterfaces(); for (Class i:ifs){ System.out.println(i); // interface java.lang.Comparable } } }
欢迎在评论区留言,欢迎关注我的CSDN @Ho1aAs