java反射基础
1. 第一步的核心是获取Class
常规情况下,一个class的二进制文件唯一对应jvm中的一个class对象,class的加载大部分情况都是jvm自动处理,对于动态加载的情况,一种是通过Class.forName,另一种是通过ClassLoader.loadClass(),这两种方式都可以加载classpath下的class二进制文件,关于classpath的获取
How to print out the current project classpath
Find where java class is loaded from
ClassLoader.loadClass()的优势是可以自定义ClassLoader,以实现自定义class二进制字节码的加载地址,比如实现加载网络上的class二进制文件。
以下方式都会返回Class的实例
Class.forName()
ClassLoader.loadClass()
ClassName.class
objectName.getClass()
2. 获取class简要信息
void checkClass(String className) throws ClassNotFoundException { Class bclass = Class.forName(className); System.out.println("class name: " + bclass.getSimpleName()); System.out.println(); int modifier = bclass.getModifiers(); System.out.println("is class public: " + Modifier.isPublic(modifier)); System.out.println(); Package pac = bclass.getPackage(); System.out.println("package name: " + pac.getName()); System.out.println(); Class sclass = bclass.getSuperclass(); System.out.println("super class: " + sclass.getName()); System.out.println(); Class[] inters = bclass.getInterfaces(); System.out.println("implemented interface: "); for (Class cls : inters) System.out.println("\t" + cls.getName()); System.out.println(); Constructor[] constructors = bclass.getConstructors(); System.out.println("constructors:"); for (Constructor c : constructors) { System.out.println("\t" + c.getName()); for (Class cls : c.getParameterTypes()) System.out.println("\t\tparam type: " + cls.getName()); } System.out.println(); System.out.println("own methods:"); for (Method mth : bclass.getDeclaredMethods()) { System.out.println("\t" + mth.getName()); for (Class cls : mth.getParameterTypes()) System.out.println("\t\tparam types: " + cls.getName()); System.out.println("\t\treturn types: " + mth.getReturnType().getName()); } System.out.println(); System.out.println("fields:"); for (Field f : bclass.getFields()) { System.out.print("\t" + f.getName()); System.out.println("\t:" + f.getType().getName()); } }
refer Java Reflection
3. 通过反射的方式查看Object里面的变量
1) getFields可以获取所有的public类型成员变量,包含所有父类的public变量
2) getDeclaredFields可以获取当前类的所有成员变量,包含private类型,但是不包含父类
以下通过循环的方式获取所有成员变量的信息
static Map<String, Object> objectToMap(Object object) { Map<String, Object> map = new HashMap<>(); Class cls = object.getClass(); while (cls != null) { System.out.println(cls.getName()); for (Field field : cls.getDeclaredFields()) { field.setAccessible(true); Object value = null; try { value = field.get(object); } catch (IllegalAccessException e) { e.printStackTrace(); } System.out.println(field.getName() + " # " + value); if (value != null) map.put(field.getName(), value); } cls = cls.getSuperclass(); System.out.println("====================="); } return map; }
4. 通过反射的方式创建一个新的对象
假设有一个class
public class MyObject { private int code; private String msg; public MyObject(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } }
1) MyObject可能会有子类,所有的子类都会有(int, String)这样的构造函数,那么所有的子类都可以通过如下的方式创建
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { MyObject object = newInstance(MyObject.class, 1, "succ"); System.out.println(object.getCode() + " # " + object.getMsg()); } static MyObject newInstance(Class<? extends MyObject> classType, int code, String msg) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Constructor<? extends MyObject> constructor = classType.getConstructor(int.class, String.class); return constructor.newInstance(code, msg); }
2) 通过Class的newInstance()方式创建一个对象,前提是该Class有默认构造函数或无参构造函数