Java反射机制简介

目录

反射操作类

Class类

属性类

方法类

反射示例

对象分析

类定义

数组Copy


反射库提供了丰富的工具集,以便编写能动态操纵Java代码的程序(JavaBean中即大量应用)。通过反射,可以知道任意类的所有属性和方法,调用对象的属性和方法。反射机制可以:

  • 在运行时分析类的能力;
  • 在运行时查看对象;
  • 实现通用的数组操作代码;
  • 利用Method对象:调用函数;

反射操作类

java.lang.reflect包中封装了反射相关的操作类:

  • Class:类的实体;
  • Field:类的成员变量(属性);
  • Method:类的方法;
  • Constructor:类的构造方法;

Class类

Class类代表类的实体,在运行的应用程序中表示类和接口。一些重要方法:

  • getClassLoader():获取类的加载器;
  • getClasses():获取类中包含的所有公共类和接口;
  • getDeclaredClasses():获取类中包含的所有类和接口;
  • forName(String className):根据类名返回类对象;
  • getName():返回类的完整名(getSimpleName:仅类名,不包括包名);
  • newInstance():创建类实例;
  • getPackage():获取包名;
  • getSuperClass():获取当前类的父类;
  • getInterfaces():获取当前类实现的类或接口;
  • get[Declared]Fields:获取公开/全部属性;
  • get[Declared]Constructors:获取公开/全部构造方法
  • get[Declared]Methods:获取公开/全部方法

对于数组(使用isArray判断),getName返回的是内部定义的类型(不易识别),此时需要通过getComponentType来获取数组元素对应类型。

属性类

Field类代表类的属性:

  • get(Object obj):获取obj对象中对应属性值;
  • set(Object obj, Object value):设定obj对象中对应属性值;

默认属性是不允许随意操作,需要通过AccessibleObject.setAccessible(fields, true)设定允许后才可以get/set。

方法类

Method代表类的方法,通过invoke来调用对应方法;
Constructor代表构造方法,通过newInstance调用对应构造方法;

反射示例

对象分析

获取对象内属性的值,为避免对象内出现循环引用,增加一个链表记录已访问过的属性。

static String ObjectAnalyzer(Object obj) {
    List<Object> lstVisisted = new ArrayList<>();
    return ObjectAnalyzer(obj, lstVisisted);
}

static String ObjectAnalyzer(Object obj, List<Object> visited) {
    if (obj == null)
        return "null";
    if (visited.contains(obj))
        return "...";
    visited.add(obj);
    Class<?> cl = obj.getClass();
    if (cl == String.class)
        return (String) obj;
    if (cl.isArray()) {
        String r = cl.getComponentType() + "[]{";
        for (int i = 0; i < Array.getLength(obj); i++) {
            if (i > 0)
                r += ", ";
            Object val = Array.get(obj, i);
            if (cl.getComponentType().isPrimitive())
                r += val;
            else
                r += ObjectAnalyzer(val, visited);
        }
        return r + "}";
    }

    String r = cl.getName();
    // inspect the fields of this class and all superclasses
    do {
        r += "{";
        Field[] fields = cl.getDeclaredFields();
        AccessibleObject.setAccessible(fields, true);
        // get the names and values of all fields
        for (Field f : fields) {
            if (!Modifier.isStatic(f.getModifiers())) {
                if (!r.endsWith("{"))
                    r += ", ";
                r += f.getName() + "=";
                try {
                    Class<?> t = f.getType();
                    Object val = f.get(obj);
                    if (t.isPrimitive())
                        r += val;
                    else
                        r += ObjectAnalyzer(val, visited);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        if (r.endsWith("{"))
            r = r.substring(0, r.length() - 1);
        else
            r += "}";

        cl = cl.getSuperclass();
    } while (cl != null);

    return r;
}

如我们分析一个日期时间对象,会返回其属性(若为对象类型则显示其对象类名)与对应值:

ObjectAnalyzer(LocalDateTime.now())
// java.time.LocalDateTime{date=java.time.LocalDate{year=2020, month=3, day=19}, time=java.time.LocalTime{hour=22, minute=59, second=25, nano=517000000}}

类定义

通过反射类,获取类的定义信息(构造方法、属性和方法):

  • 嵌套类与父类之间使用$分割:类似Outer$Nested
  • 数组需要特殊处理:int[]默认返回[I类型;
private static void ClassReflection(String name) {
    try {
        // print class name and superclass name (if != Object)
        Class<?> cl = Class.forName(name);
        Class<?> supercl = cl.getSuperclass();
        String modifiers = Modifier.toString(cl.getModifiers());
        if (modifiers.length() > 0)
            System.out.print(modifiers + " ");
        System.out.print("class " + name);
        if (supercl != null && supercl != Object.class)
            System.out.print(" extends " + supercl.getName());

        System.out.print("\n{\n");
        printConstructors(cl);
        System.out.println();
        printMethods(cl);

        System.out.println();
        printFields(cl);
        System.out.println("}");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

public static void printConstructors(Class<?> cl) {
    Constructor<?>[] constructors = cl.getDeclaredConstructors();
    for (Constructor<?> c : constructors) {
        String name = c.getName();
        System.out.print(Indent_Blank);
        String modifiers = Modifier.toString(c.getModifiers());
        if (modifiers.length() > 0)
            System.out.print(modifiers + " ");
        System.out.print(name + "(");
        // print parameter types
        Class<?>[] paramTypes = c.getParameterTypes();
        for (int j = 0; j < paramTypes.length; j++) {
            if (j > 0)
                System.out.print(", ");
            System.out.print(getRealTypeName(paramTypes[j]));
        }
        System.out.println(");");
    }
}

public static void printMethods(Class<?> cl) {
    Method[] methods = cl.getDeclaredMethods();
    for (Method m : methods) {
        Class<?> retType = m.getReturnType();
        String name = m.getName();
        System.out.print(Indent_Blank);
        String modifiers = Modifier.toString(m.getModifiers());
        if (modifiers.length() > 0)
            System.out.print(modifiers + " ");
        System.out.print(getRealTypeName(retType) + " " + name + "(");

        Class<?>[] paramTypes = m.getParameterTypes();
        for (int j = 0; j < paramTypes.length; j++) {
            if (j > 0)
                System.out.print(", ");
            System.out.print(getRealTypeName(paramTypes[j]));
        }
        System.out.println(");");
    }
}

public static void printFields(Class<?> cl) {
    Field[] fields = cl.getDeclaredFields();
    for (Field f : fields) {
        Class<?> type = f.getType();
        String typeName = getRealTypeName(type);
        System.out.print(Indent_Blank);
        String modifiers = Modifier.toString(f.getModifiers());
        if (modifiers.length() > 0)
            System.out.print(modifiers + " ");
        System.out.println(typeName + " " + f.getName() + ";");
    }
}

private static String getRealTypeName(Class<?> type) {
    String typeName;
    if (type.isArray()) {
        typeName = type.getComponentType().getName() + "[]";
    } else {
        typeName = type.getName();
    }
    return typeName;
}

数组Copy

为了复制数组我们需要先获取数组的真实类型与长度(通过Array类获取)。

static Object ArrayCopyOf(Object ary, int newLength) {
    Class<?> cl = ary.getClass();
    if (!cl.isArray())
        return null;
    Class<?> componentType = cl.getComponentType();
    int length = Array.getLength(ary);
    Object newArray = Array.newInstance(componentType, newLength);
    System.arraycopy(ary, 0, newArray, 0, Math.min(length, newLength));
    return newArray;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值