Java反射
Java反射API
获取Class对象
通过反射创建实例对象,调用公共方法
通过反射调用私有方法
一.Java反射API
java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。即:通过class文件对象,去使用该文件中的成员变量、构造方法、成员方法。
1.java.lang.class类
java.lang.Class主要提供了以下两个功能:
提供方法用于访问运行期间类的元数据;
提供方法用于检查和修改类的运行时行为;
2.java.lang.class类常用方法
Method Des public String getName() 返回类名 public static Class forName(String className)throws ClassNotFoundException 加载类并返回Class对象 public Object newInstance()throws InstantiationException,IllegalAccessException 创建实例对象 public boolean isInterface() 判断是否是接口 public boolean isArray() 判断是否是数组 public boolean isPrimitive() 判断是否是原始数据类型 public Class getSuperclass() 返回父类Class引用 Field getDeclaredField(String name) throws NoSuchMethodException,SecurityException 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。 Field[] getDeclaredFields() throws SecurityException 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。 Field getField(String name) throws SecurityException 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。 Field[] getFields() throws SecurityException 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。 Constructor<T> getDeclaredContructor(Class<?>... paramTypes) throws NoSuchMethodException,SecurityException 返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。 Constructor<?>[] getDeclaredContructors() throws SecurityException 返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。 Constructor<T> getContructor(Class<?>... paramTypes) throws SecurityException 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。 Constructor<?>[] getContructors() throws SecurityException 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。 Method getDeclaredMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException,SecurityException 返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法(不分什么修饰符修饰,都可以获取到)。 Method[] getDeclaredMethods() throws SecurityException 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 Method getMethod(String name, Class<?>... parameterTypes) throws SecurityException 返回一个 Method 对象,返回此 Class 对象所表示的类或接口的公共成员方法。 Method[] getMethods() throws SecurityException 返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口的公共成员方法。
二.获取Class对象
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法。所以先要获取到每一个字节码文件对应的Class对应的Class类型的对象
1.Class类的静态方法forName(),根据全类名获取Class对象
动态加载,运行时,开始装入类,并做类的静态初始化。
知道类的全限定名时,可以使用该方式。注意原始数据类型不适用该方法。
public class GetClass { public static void main(String[] args) throws ClassNotFoundException { Class<?> c = Class.forName("swu.xl.day_18_self_Fanshe.GetClass"); System.out.println(c.getName()); System.out.println(c.getSimpleName()); } } 输出结果: swu.xl.day_18_self_Fanshe.GetClass GetClass
2.Object类的getClass()方法
静态加载(编译时已加载)。
从实例对象中获取Class对象。
public class GetClass { public static void main(String[] args) { GetClass g = new GetClass(); Class<? extends GetClass> c = g.getClass(); System.out.println(c.getName()); System.out.println(c.getSimpleName()); } } 输出结果: swu.xl.day_18_self_Fanshe.GetClass GetClass
3.数据类型(基本和引用)的静态属性class
静态加载(编译时已加载)
作用于类名上,也可应用于原始数据类型。
public class GetClass { public static void main(String[] args) { Class<Boolean> c = boolean.class; System.out.println(c.getName()); Class<GetClass> t = GetClass.class; System.out.println(t.getName()); } }
4.选择
一般,开发中使用第一种,因为第一种是一个字符串,而不是一个具体的类名。这样就可以把这样的字符串配置到配置文件中。
5.使用
Class类:常用类
成员变量:Field
构造方法: Constructor
成员方法:Method
反射:通过Class类的方法获取以上的三个对应的对象,然后通过Filed/Method/Contructor对象调用其方法去真正的使用类的成员、方法、构造
三.通过反射创建实例对象,调用公共方法
1.通过Class对象的newInstance()方法创建,这种方式只能调用无参构造方法
public class GetClass { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { //获得Class对象 Class<?> c = Class.forName("swu.xl.day_18_self_Fanshe.Test"); //创建实例对象 Test o = (Test)c.newInstance(); //调用方法 o.message(); } } public class Test { public void message(){ System.out.println("test success"); } } 运行结果: test success
2.通过Constructor对象的newInstance()方法创建,这种方式适用于有参构造方法,并且还可以破坏单例模式,调用私有构造方法
注意这里可以根据传入参数的类型来得到指定的构造方法。还可以使用setAccessible修改访问权限。
<public void setAccessible(boolean flag) throws SecurityException
将此对象的标志设置为true则表示反射的对象在使用时应该取消 Java 语言访问检查。public class GetClass { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { //获得Class对象 Class<?> c = Class.forName("swu.xl.day_18_self_Fanshe.Test"); //得到反映此Class对象所表示的类或接口的指定构造方法 Constructor<?> con = c.getDeclaredConstructor(String.class,Integer.class); //取消Java语言访问检查 con.setAccessible(true); //创建实例对象 Test o = (Test)con.newInstance(" message",5); //调用方法 o.message(); } } public class Test { //私有成员变量 private String msg; private Integer num; //私有构造方法 private Test(String msg,Integer num){ this.msg = msg; this.num = num; } //方法 public void message(){ System.out.println("Get successful"+msg+" "+num+"条信息"); } } 运行结果: Get successful message 5条信息
四.通过反射调用私有方法
通过反射,我们可以调用其它类的私有方法,主要涉及java.lang.Class和java.lang.reflect.Method类。
其中主要是用到了Method类的setAccessible方法和invoke方法,前者修改访问权限,后者调用方法。
public class GetClass { public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { //获得Class对象 Class<?> c = Class.forName("swu.xl.day_18_self_Fanshe.Test"); //得到反映此Class对象中给定参数的构造方法 Constructor<?> con = c.getDeclaredConstructor(String.class,Integer.class); //取消Java语言访问检查 con.setAccessible(true); //创建实例对象 Test o = (Test)con.newInstance("messages",5); //得到反映此Class对象中给定名字以及参数的方法 Method message = c.getDeclaredMethod("message", new Class[]{int.class}); //取消Java语言访问检查 message.setAccessible(true); //调用私有方法 message.invoke(o,5); } } public class Test { //私有成员变量 private String msg; private Integer num; //私有构造方法 private Test(String msg,Integer num){ this.msg = msg; this.num = num; } //私有方法 private void message(int count){ System.out.println("Get " +num +" successful"+" "+msg+" "+count+"条信息没有收到"); } } 运行结果: Get 5 successful messages 5条信息没有收到
参考文章:
网友评论