5.7 反射

保存类信息的类是Class

getClass()将返回一个调用对象相关的Class实例

Class对象表示的是一种类型,这个类型不一定是对象类型,例如 int.class 是一个Class类型对象

虚拟机为每个类型管理一个Class对象,因此可以直接使用 == 来进行比较

    Employee e = new Employee();
    e.getClass().newInstance();

newInstance方法创建了一个和 e 相同类型的实例,将会调用默认构造器,如果没有默认构造器将抛出异常

Class类中的getFields、getMethods和getConstructors方法将分别返回类提供的public域、方法和构造器数组且包括基类的公有成员
getDeclareFields、getDeclareMethods和getDeclareConstructors将返回类中声明的域、方法和构造器,包括private和protected,但不包括基类成员

getModifiers将会返回一个int类型的值,再使用Modifier类的 toString方法可以得到,域、方法和构造器前修饰的关键字

下面的类通过反射根据类名来解析类中的构造器、方法、域

public class ClassAnalyzer {

    private final String tab = "    ";

    public String toString(String className) {
        Class cl = null;
        try {
            cl = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return this.toString(cl);
    }

    public String toString(Class cl) {
        StringBuilder builder = new StringBuilder();
        Class supercl = cl.getSuperclass();
        int classInt = cl.getModifiers();
        String classModifier = Modifier.toString(classInt);
        if (classModifier.length() > 0) {
            builder.append(classModifier).append(" ");
        }
        builder.append("class ").append(cl.getName());
        if (supercl != null && supercl != Object.class) {
            builder.append(" extends ").append(supercl.getName());
        }
        StringBuilder consBuilder = printConstructors(cl);
        StringBuilder methodsBuilder = printMethods(cl);
        StringBuilder fieldsBuilder = printFields(cl);
        builder.append(" {\n").append(fieldsBuilder).append(methodsBuilder).append(consBuilder).append("}");
        return builder.toString();
    }

    private StringBuilder printConstructors(Class cl) {
        StringBuilder builder = new StringBuilder();
        Constructor[] constructors = cl.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            String name = constructor.getName();
            builder.append(tab);
            int constructorInt = constructor.getModifiers();
            String consModifier = Modifier.toString(constructorInt);
            if (consModifier.length() > 0) {
                builder.append(consModifier).append(" ");
            }
            builder.append(name).append(" (");
            Class[] paramTypes = constructor.getParameterTypes();
            for (int i = 0; i < paramTypes.length; i++) {
                if (i > 0) {
                    builder.append(", ");
                }
                builder.append(paramTypes[i].getName());
            }
            builder.append(");\n");
        }
        return builder;
    }

    private StringBuilder printMethods(Class cl) {
        StringBuilder builder = new StringBuilder();
        Method[] methods = cl.getDeclaredMethods();
        for (Method method : methods) {
            Class returnType = method.getReturnType();
            String typeName = returnType.getName();
            if (typeName.startsWith("[")){//数组会显示为[开头
                typeName = typeName.substring(2);
                typeName = typeName.replace(";", "[]");//将;结尾替换为[]结尾
            }
            String name = method.getName();
            builder.append(tab);
            int methodInt = method.getModifiers();
            String methodModifier = Modifier.toString(methodInt);
            if (methodModifier.length() > 0) {
                builder.append(methodModifier).append(" ");
            }
            builder.append(typeName).append(" ").append(name).append(" (");
            Class[] paramTypes = method.getParameterTypes();
            for (int i = 0; i < paramTypes.length; i++) {
                if (i > 0) {
                    builder.append(", ");
                }
                builder.append(paramTypes[i].getName());
            }
            builder.append(");\n");
        }
        return builder;
    }

    private StringBuilder printFields(Class cl) {
        StringBuilder builder = new StringBuilder();
        Field[] fields = cl.getDeclaredFields();
        for (Field field : fields) {
            Class type = field.getType();
            String typeName = type.getName();
            if (typeName.startsWith("[")){
                typeName = typeName.substring(2);
                typeName = typeName.replace(";", "[]");
            }
            String name = field.getName();
            builder.append("    ");
            int fieldInt = field.getModifiers();
            String fieldModifier = Modifier.toString(fieldInt);
            if (fieldModifier.length() > 0) {
                builder.append(fieldModifier).append(" ").append(typeName).append(" ");
            }
            builder.append(name).append("\n");
        }
        return builder;
    }
}

返回值如下

public class Chapter5.Employee {
    private double salary
    private java.time.LocalDate hireday
    private java.lang.String name
    private Chapter5.Workday[] workdays
    public void raiseSalary (double);
    public Chapter5.Employee (double, java.lang.String, int, int, int);
}

以上是对类进行解析,如果要对类的某个对象进行解析呢

	   try {
            Employee stark = new Employee(2000, "stark", 2020, 5, 22);
            Class employee = stark.getClass();
            Field name = employee.getDeclaredField("name");
            Object starkName = name.get(stark);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        //运行将会抛出异常Class Main can not access a member of class Chapter5.Employee with modifiers "private"

异常原因就是Employee中的name属性访问权限为private
但是使用反射可以绕开这个限制来获取它的值,使用setAccessible(true)

	   try {
            Employee stark = new Employee(2000, "stark", 2020, 5, 22);
            Class employee = stark.getClass();
            Field name = employee.getDeclaredField("name");
            name.setAccessible(true);
            Object starkName = name.get(stark);//starkName实际是字符串"stark"
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

下方的类通过反射对对象进行解析

public class ObjectAnalyzer {
    private ArrayList visited = new ArrayList<>();

    //将对象的详细信息处理成字符串返回
    public String toString(Object obj) {
        if (obj == null) {
            return "null";
        }
        //防止数组,list等存放自身的引用
        if (visited.contains(obj)) {
            return "...";
        }
        visited.add(obj);
        Class cl = obj.getClass();
        if (cl == String.class) {
            return (String) obj;
        }
        if (cl.isArray()) {
            StringBuilder result = new StringBuilder(cl.getComponentType().toString());
            result.append("[]{");
            for (int i = 0; i < Array.getLength(obj); i++) {
                if (i > 0) {
                    result.append(",");
                }
                Object val = Array.get(obj, i);
                if (cl.getComponentType().isPrimitive()) {
                    result.append(val);
                } else {
                    result.append(toString(val));//递归调用
                }

            }
            return result.append("}").toString();
        }

        String clName = cl.getName();
        StringBuilder result = new StringBuilder(clName);
        do {
            result.append("[");
            Field[] fields = cl.getDeclaredFields();
            AccessibleObject.setAccessible(fields, true);
            for (Field field : fields) {
                if (!Modifier.isStatic(field.getModifiers())) {
                    if (!result.toString().endsWith("[")) {
                        result.append(",");
                    }
                    result.append(field.getName()).append("=");
                    try {
                        Class t = field.getType();
                        Object val = field.get(obj);
                        if (t.isPrimitive()) {
                            result.append(val.toString());
                        } else {
                            result.append(toString(val));//如果是对象引用则递归
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            result.append("]");
            cl = cl.getSuperclass();//获取父类信息
        } while (cl != null && cl != Object.class);//不把Object算在父类中
        return result.toString();
    }
}
 
 

除了解析类和对象外,通过反射还能调用任意方法,当然,这是不推荐使用的

你可能感兴趣的:(5.7 反射)