0%

Java反射

Java反射机制可以在我们运行时期获取任何一个类的各种信息。如属性,方法等。还能动态调用类中的方法,动态操作运行中类的属性。

不过使用反射最大的弊端是性能比较差,反射的操作会比直接操作慢好多。

基本用法

  1. 获取Class对象

在使用反射之前要先获取要操作的类对象。

定义了一个类,里面有一个int的属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

public class MyClass {
private int property;

public MyClass(int property) {
this.property = property;
}
public int getProperty() {
return property;
}

public void setProperty(int property) {
this.property = property;
}
}
  1. 获取MyClass对象

    一种是通过已经创建的MyClass对象直接获取
    还有一种通过MyClass的完整类名去获取。
    当然直接 类名.class 也能够获取

    1
    2
    3
    4
    5
    6
    // 通过已创建的MyClass获取
    Class myClass = MyClass.getClass();
    // 通过forName获取
    Class myClass = Class.forName("util.MyClass");

    Class myClass = MyClass.class;
  2. 获取执行类的属性、方法等
    获取:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 获取所有属性
    Field[] fields = myClass.getFields();

    //获取当前类自己定义的属性
    Field[] declaredFields = myClass.getDeclaredFields();

    // 获取所有方法
    Method[] methods = myClass.getMethods();

    // 获取本类中自己定义的方法
    Method[] declaredmethods = myClass.getMethods();

    // 获取继承的父类
    Class fatherClass = myClass.getSuperclass();

    // 获取实现的接口
    Class[] InterfaceClass = myClass.getInterfaces();

    执行:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    MyClass myClassObject = new MyClass(1);
    Class myClass = myClassObject.getClass();
    // 获取setProperty方法
    Method setProperty = myClass.getDeclaredMethod("setProperty",int.class);
    // 对setProperty方法取消安全检查,如果setProperty方法是private的话,就必须要设置这个才能使用
    setProperty.setAccessible(true);
    // 执行方法,将property设置成了10,第一个参数是要执行的Object类,第二个参数是方法参数(可以有多个)
    setProperty.invoke(myClassObject,10);

    Method getProperty = myClass.getDeclaredMethod("getProperty",null);
    // 通过执行getProperty看一下有没有通过反射把值设置成功
    int result = (int) getProperty.invoke(myClassObject,null);

    上面就是java反射机制简单介绍。

    下面结合我具体做过的案例介绍一下。

    具体案例

    使用DataTable作为前端图表插件,后端持久层用的MyBatis

    因为每次要分页的时候都需要对java实体类进行各种拼装参数的操作,重复的劳动我就索性使用反射把实体类给封装了。

    父类:

    1
    2
    3
    4
    5
    6
    7
    8
    9

    public class DataTable {
    private Integer iDisplayStart; //分页 从数据库 第几条开始
    private Integer iDisplayLength; //分页 从数据库中获取多少条
    private int iSortCol_0; // 排序列 获取的是列的下标,从0 开始,包括不可排序的列
    private String sSortDir_0; // 排序 该列的排序方式desc asc
    private String sSearch;
    // ...getXX()、setXXX()
    }

    子类

    1
    2
    3
    4
    5
    6
    7

    public class AccidentList extends DataTable {
    private Integer id;
    private String orderNo;
    private String dept;
    private String accident;
    // ...getXX()、setXXX()

    封装:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403

    public class Pagging {
    /**
    * 通过反射设置分页信息
    *
    * @param example
    * @param model
    * @return
    */
    public static Object getPageData(Object example, Object model, String[] params) {
    try {
    Field setOffset = example.getClass().getDeclaredField("offset");
    setOffset.setAccessible(true);
    Field setLimit = example.getClass().getDeclaredField("limit");
    setLimit.setAccessible(true);
    Field setOrderByClause = example.getClass().getDeclaredField("orderByClause");
    setOrderByClause.setAccessible(true);
    if (((DataTable) model).getiDisplayStart() != null && ((DataTable) model).getiDisplayLength() != null && ((DataTable) model).getsSearch() != null) {
    Field getiDisplayStart = model.getClass().getSuperclass().getDeclaredField("iDisplayStart");
    getiDisplayStart.setAccessible(true);
    Field getiDisplayLength = model.getClass().getSuperclass().getDeclaredField("iDisplayLength");
    getiDisplayLength.setAccessible(true);
    Field getsSearch = model.getClass().getSuperclass().getDeclaredField("sSearch");
    getsSearch.setAccessible(true);
    // 设置分页
    setOffset.set(example, getiDisplayStart.get(model));
    setLimit.set(example, getiDisplayLength.get(model));
    // 设置排序
    String a = (String) model.getClass().getSuperclass().getDeclaredMethod("getsSortDir_0").invoke(model);
    Integer b = (Integer) model.getClass().getSuperclass().getDeclaredMethod("getiSortCol_0").invoke(model);
    setOrderByClause.set(example, params[b] + " " + a);
    // 设置搜索
    for (int i = 0; i < params.length; i++) {
    Object criteria = example.getClass().getDeclaredMethod("or").invoke(example);
    String p = params[i];
    try {
    ReflectUtils.invokePrivateMethod(criteria, StringUtil.camelName("and_" + p + "_like"), String.class, "%" + getsSearch.get(model) + "%");
    ReflectUtils.invokePrivateMethod(criteria, "andIsShowEqualTo", Integer.class, 1);
    } catch (Exception e) {
    try {
    ReflectUtils.invokePrivateMethod(criteria, StringUtil.camelName("and_" + p + "_equal_to"), Integer.class, Integer.valueOf((String) getsSearch.get(model)));
    ReflectUtils.invokePrivateMethod(criteria, "andIsShowEqualTo", Integer.class, 1);
    } catch (Exception no) {

    }
    }
    }
    }
    } catch (Exception e) {
    e.printStackTrace();
    }
    return example;
    }
    }

    public class ReflectUtils {
    /**
    * 创建类的实例,调用类的无参构造方法
    *
    * @param className
    * @return
    */
    public static Object newInstance(String className) {

    Object instance = null;

    try {
    Class<?> clazz = Class.forName(className);
    instance = clazz.newInstance();
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    } catch (InstantiationException e) {
    // if this Class represents an abstract class, an interface, an
    // array class, a primitive type, or void; or if the class has no
    // nullary constructor; or if the instantiation fails for some other
    // reason.

    e.printStackTrace();
    } catch (IllegalAccessException e) {
    // if the class or its nullary constructor is not accessible
    e.printStackTrace();
    }

    return instance;

    }

    /**
    * 获取所有的public构造方法的信息
    *
    * @param className
    * @return
    */
    public static String getPublicConstructorInfo(String className) {
    StringBuilder sBuilder = new StringBuilder();

    try {
    Class<?> clazz = Class.forName(className);
    Constructor<?>[] constructors = clazz.getConstructors();
    sBuilder.append(getConstructorInfo(constructors));
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    }

    return sBuilder.toString();
    }

    /**
    * 得到本类内声明的构造方法信息
    *
    * @param className
    * @return
    */
    public static String getDeclearedConstructorInfo(String className) {
    StringBuilder sBuilder = new StringBuilder();

    try {
    Class<?> clazz = Class.forName(className);
    Constructor<?>[] constructors = clazz.getDeclaredConstructors();
    sBuilder.append(getConstructorInfo(constructors));
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    }

    return sBuilder.toString();
    }

    /**
    * 获取public的字段信息
    *
    * @param className
    * @return
    */
    public static String getPublicFieldInfo(String className) {
    StringBuilder sBuilder = new StringBuilder();

    try {
    Class<?> clazz = Class.forName(className);

    Field[] fields = clazz.getFields();
    sBuilder.append(getFieldInfo(fields));
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    }

    return sBuilder.toString();
    }

    /**
    * 获取本类内声明的字段信息
    *
    * @param className
    * @return
    */
    public static String getDecleardFieldInfo(String className) {
    StringBuilder sBuilder = new StringBuilder();

    try {
    Class<?> clazz = Class.forName(className);

    Field[] fields = clazz.getDeclaredFields();
    sBuilder.append(getFieldInfo(fields));
    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    }

    return sBuilder.toString();
    }

    /**
    * 得到所有public方法信息
    *
    * @param className
    * @return
    */
    public static String getPublicMethodInfos(String className) {
    StringBuilder sBuilder = new StringBuilder();

    try {
    Class<?> clazz = Class.forName(className);
    Method[] methods = clazz.getMethods();// 得到所有的public方法,包括从基类继承的

    sBuilder.append(getMethodInfo(methods));

    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    }

    return sBuilder.toString();
    }

    /**
    * 得到类内声明的方法信息
    *
    * @param className
    * @return
    */
    public static String getDeclaredMethodInfos(String className) {

    StringBuilder sBuilder = new StringBuilder();
    try {
    Class<?> clazz = Class.forName(className);
    Method[] methods = clazz.getDeclaredMethods();// 得到本类声明的所有方法,包括私有方法
    // clazz.getMethods(); 会返回所有public的方法,但是包括基类Object的方法

    sBuilder.append(getMethodInfo(methods));

    } catch (ClassNotFoundException e) {
    e.printStackTrace();
    } catch (Exception e) {
    e.printStackTrace();
    }

    return sBuilder.toString();
    }

    /**
    * 得到构造器信息
    *
    * @param constructor
    * @return
    */
    private static String getConstructorInfo(Constructor<?> constructor) {

    StringBuilder sBuilder = new StringBuilder();

    sBuilder.append("name: " + constructor.getName());
    sBuilder.append("\ngetParameterTypes: "
    + Arrays.toString(constructor.getParameterTypes()));
    return sBuilder.toString();
    }

    /**
    * 将一组构造器的信息组成一个字符串返回
    *
    * @param constructors
    * @return
    */
    private static String getConstructorInfo(Constructor<?>[] constructors) {

    StringBuilder sBuilder = new StringBuilder();
    int i = 0;
    for (Constructor<?> c : constructors) {
    sBuilder.append("method: " + ++i + " : ");
    sBuilder.append("\n" + getConstructorInfo(c));
    sBuilder.append("\n");
    }

    return sBuilder.toString();

    }

    /**
    * 获取字段信息,组成一个字符串返回
    *
    * @param field
    * @return
    */
    private static String getFieldInfo(Field field) {
    StringBuilder sBuilder = new StringBuilder();
    sBuilder.append("name: " + field.getName());
    sBuilder.append("\ngetType: " + field.getType());
    sBuilder.append(getModifiersInfo(field));
    return sBuilder.toString();
    }

    /**
    * 获取一组字段的信息,返回字符串
    *
    * @param fields
    * @return
    */
    private static String getFieldInfo(Field[] fields) {
    StringBuilder sBuilder = new StringBuilder();
    int i = 0;
    for (Field field : fields) {
    sBuilder.append("field: " + ++i + " : ");
    sBuilder.append("\n" + getFieldInfo(field));
    sBuilder.append("\n");
    }

    return sBuilder.toString();
    }

    /**
    * 获取方法的信息,组成一个字符串返回
    *
    * @param method
    * @return
    */
    private static String getMethodInfo(Method method) {

    StringBuilder sBuilder = new StringBuilder();

    sBuilder.append("name: " + method.getName());
    sBuilder.append("\ngetReturnType: " + method.getReturnType());
    sBuilder.append("\ngetParameterTypes: "
    + Arrays.toString(method.getParameterTypes()));
    sBuilder.append(getModifiersInfo(method));
    return sBuilder.toString();
    }

    /**
    * 获取一组方法的信息,组成一个字符串返回
    *
    * @param methods
    * @return
    */
    private static String getMethodInfo(Method[] methods) {
    StringBuilder sBuilder = new StringBuilder();
    int i = 0;
    for (Method method : methods) {

    sBuilder.append("method: " + ++i + " : ");
    sBuilder.append("\n" + getMethodInfo(method));
    sBuilder.append("\n");

    }

    return sBuilder.toString();
    }

    /**
    * 获取修饰符信息
    *
    * @param member
    * @return
    */
    private static String getModifiersInfo(Member member) {
    StringBuilder sBuilder = new StringBuilder();
    int modifiers = member.getModifiers();
    sBuilder.append("\ngetModifiers: " + +modifiers + ", ");// 得到修饰符编码
    sBuilder.append("\nisPublic: " + Modifier.isPublic(modifiers) + ", ");
    sBuilder.append("\nisPrivate: " + Modifier.isPrivate(modifiers) + ", ");
    sBuilder.append("\nisStatic: " + Modifier.isStatic(modifiers) + ", ");
    sBuilder.append("\nisFinal: " + Modifier.isFinal(modifiers) + ", ");
    sBuilder.append("\nisAbstract: " + Modifier.isAbstract(modifiers));

    return sBuilder.toString();
    }

    /**
    * 是否是公用静态方法
    *
    * @param member
    * @return
    */
    private static boolean isPublicStatic(Member member) {
    boolean isPS = false;
    int mod = member.getModifiers();
    isPS = Modifier.isPublic(mod) && Modifier.isStatic(mod);
    return isPS;
    }

    /**
    * 调用静态方法
    *
    * @param className
    * @param methodName
    * @param paramTypes
    * @param params
    * @return
    * @throws Exception
    */
    public static Object invokePublicStaticMethod(String className,
    String methodName, Class<?>[] paramTypes, Object[] params)
    throws Exception {

    Class<?> cls = Class.forName(className);

    Method method = cls.getMethod(methodName, paramTypes);
    Object value = null;
    if (isPublicStatic(method)) {
    value = method.invoke(null, params);
    }

    return value;
    }
    /**
    * 调用私有方法
    *
    * @param obj 调用类对象
    * @param methodName 方法名
    * @param paramTypes 参数类型
    * @param params 参数
    * @return
    * @throws Exception
    */
    public static Object invokePrivateMethod(Object obj, String methodName,
    Class<?> paramTypes, Object params) throws Exception {

    Object value = null;
    Class<?> cls = obj.getClass();

    // 注意不要用getMethod(),因为getMethod()返回的都是public方法
    Method method = cls.getDeclaredMethod(methodName, paramTypes);

    method.setAccessible(true);// 抑制Java的访问控制检查

    value = method.invoke(obj, params);
    return value;
    }
    }

    使用的时候只需要:

    1
    2
    3
    4
    5
    6
    7
    8

    // 定义好排序的字段
    private static final String[] Params = {"id", "order_no", "dept", "accident","occur_date","occur_mouth","accident_type","name","age","sex","into_date","workday_loss","direct_loss","com_flag","injury_flag","rectifica_measure","handle","bullentin_attachment","report_attachment","sub_person","sub_date","us_status","update_date"};

    public List<AccidentList> getAllFileInfo(AccidentList list) {
    AccidentListExample accidentListExample = (AccidentListExample) Pagging.getPageData(new AccidentListExample(), list, Params);
    return accidentListMapper.selectByExample(accidentListExample);
    }