java bean 属性 比对 获取差异_Java系列之反射

528996acf1fdaeb4ec75c0e60bd57d96.png最近知识比较零碎,不适合整理成文,来一篇以前的关于反射的学习笔记,主要内容如下:
  1. 反射机制

  2. 反射获取类的信息

  3. 反射操作类的信息

  4. 反射获取泛型

  5. 反射获取注解信息

反射机制
Java 的反射机制是指在运行状态下,对于任意一个类,都能够知道这个类的所有属性和方法,反射是一种可在代码运行时动态获取类的信息的一种机制,可通过反射获取在编译期不可能获取到的类的信息,当一个任意类被类加载器(ClassLoader)首次加载之后会自动生成一个该类对应的 Class 对象,这个 Class 对象保存了对应类的所有信息。这种当一个任意类被类加载器加载之后,动态获取 Class 对象的信息以及动态操作 Class 对象的属性和方法的功能称之为 Java 的反射机制。Java 反射机制的关键是获取某个任意类的 Class 对象,下面的内容就是如何通过这个 Class 对象获取和动态操作类的相关信息,为了便于后文中对反射的使用,这里先创建一个 User 类供下文中使用,具体如下:
 1package com.manu.reflection.bean; 2 3/** 4 * 反射测试类 5 */ 6public class User { 7 8    private int id; 9    private String name;10    private String password;1112    public User() {13        super();14    }15    public User(int id, String name, String password) {16        super();17        this.id = id;18        this.name = name;19        this.password = password;20    }21    public int getId() {22        return id;23    }24    public void setId(int id) {25        this.id = id;26    }27    public String getName() {28        return name;29    }30    public void setName(String name) {31        this.name = name;32    }33    public String getPassword() {34        return password;35    }36    public void setPassword(String password) {37        this.password = password;38    }39    @Override40    public String toString() {41        return "User [id=" + id + ", name=" + name + ", password=" + password + "]";42    }4344}
反射获取类的信息
这里总结一下如何获取类的基本信息,如类的构造方法、属性、方法等,可通过某个类对应的 Class 对象对应的 getter 方法获取某个类的名称、构造方法、属性、方法等,下面以获取某个类的构造方法为例说明获取方式不同:
  • getConstructors:表示获取某个类中修饰符为 public 的所有构造方法,如 getFields()、getMethods() 还包括从父类继承来的 public 修饰的属性和方法。

  • getDeclaredConstructors:表示获取某个类中所有声明的构造方法,只限定于本类中。

此外,还可获取指定的构造方法、属性、方法等,下面的代码主要以获取已定义(Declared)的构造方法、属性、方法为例,参考如下:
 1/** 2 * 反射获取类的信息 3 */ 4private static void getReflectClassInfo() { 5    try { 6        //获取某个类的Class对象 7        String name = "com.manu.reflection.bean.User"; 8        Class clazz = Class.forName(name); 910        //反射获取类的名称11        System.out.println("----------反射获取类的名称----------");12        String n1 = clazz.getName();//完整路径:包名+类名 (com.manu.reflection.bean.User)13        String n2 = clazz.getSimpleName();//类名(User)14        System.out.println("获取类的名称n1:"+n1);15        System.out.println("获取类的名称n2:"+n2);1617        //反射获取类的构造方法18        System.out.println("----------反射获取类的构造方法----------");19        Constructor c1 = clazz.getDeclaredConstructor(null);20        System.out.println("获取无参构造方法:"+c1);21        Constructor c2 = clazz.getDeclaredConstructor(int.class,String.class,String.class);22        System.out.println("获取有参构造方法:"+c2);23        Constructor[] constructors = clazz.getDeclaredConstructors();24        for(Constructor c: constructors) {25            System.out.println("获取所有的构造方法:"+c);26        }2728        //反射获取类的属性29        System.out.println("----------反射获取类的属性----------");30        Field f1 = clazz.getDeclaredField("name");31        System.out.println("获取名称为name的属性:"+f1);32        Field[] fields = clazz.getDeclaredFields();33        for(Field f : fields) {34            System.out.println("获取所有的属性:"+f);35        }3637        //反射获取类的方法38        System.out.println("----------反射获取类的方法----------");39        Method m1 = clazz.getDeclaredMethod("getName", null);//获取无参方法40        Method m2 = clazz.getDeclaredMethod("setName", String.class);//获取有参方法41        System.out.println("获取方法名为getName的方法m1:"+m1);42        System.out.println("获取方法名为setName的方法m2:"+m2);43        Method[] mathods = clazz.getDeclaredMethods();44        for(Method m: mathods) {45            System.out.println("获取所有方法:"+m);46        }4748    } catch (Exception e) {49        e.printStackTrace();50    }51}
通过反射获取某个类的相关信息主要如上,来上述代码的执行结果如下:
 1----------反射获取类的名称---------- 2获取类的名称n1:com.manu.reflection.bean.User 3获取类的名称n2:User 4----------反射获取类的构造方法---------- 5获取无参构造方法:public com.manu.reflection.bean.User() 6获取有参构造方法:public com.manu.reflection.bean.User(int,java.lang.String,java.lang.String) 7获取所有的构造方法:public com.manu.reflection.bean.User() 8获取所有的构造方法:public com.manu.reflection.bean.User(int,java.lang.String,java.lang.String) 9----------反射获取类的属性----------10获取名称为name的属性:private java.lang.String com.manu.reflection.bean.User.name11获取所有的属性:private int com.manu.reflection.bean.User.id12获取所有的属性:private java.lang.String com.manu.reflection.bean.User.name13获取所有的属性:private java.lang.String com.manu.reflection.bean.User.password14----------反射获取类的方法----------15获取方法名为getName的方法m1:public java.lang.String com.manu.reflection.bean.User.getName()16获取方法名为setName的方法m2:public void com.manu.reflection.bean.User.setName(java.lang.String)17获取所有方法:public java.lang.String com.manu.reflection.bean.User.toString()18获取所有方法:public java.lang.String com.manu.reflection.bean.User.getName()19获取所有方法:public int com.manu.reflection.bean.User.getId()20获取所有方法:public void com.manu.reflection.bean.User.setName(java.lang.String)21获取所有方法:public java.lang.String com.manu.reflection.bean.User.getPassword()22获取所有方法:public void com.manu.reflection.bean.User.setId(int)23获取所有方法:public void com.manu.reflection.bean.User.setPassword(java.lang.String)
反射操作类的信息
通过 Java 的反射机制可以获取的某个类的构造方法、属性以及方法,然后就可以对该类进行相关操作了,下面是将通过 Java 的反射机制构建该类的对象、操作该类对象的属性以及调用该类对象的方法,具体参考如下:
 1/** 2 * 反射操作类的信息 3 */ 4private static void setReflectClassInfo() { 5    try { 6        //获取某个类的Class对象 7        String name = "com.manu.reflection.bean.User"; 8        Class clazz = Class.forName(name); 910        //反射操作类的构造方法11        System.out.println("----------反射操作类的构造方法----------");12        Constructor c1 = clazz.getDeclaredConstructor(null);//获取无参构造方法13        Constructor c2 = clazz.getDeclaredConstructor(int.class,String.class,String.class);//获取带参构造方法14        User u1 = c1.newInstance();15        User u2 = c2.newInstance(1000,"jzman-blog","111111");16        System.out.println("u1:"+u1);17        System.out.println("u2:"+u2);1819        //反射操作类的属性20        System.out.println("----------反射操作类的属性----------");21        User u3 = c1.newInstance();22        Field field = clazz.getDeclaredField("name");23        field.setAccessible(true);//设置该属性不需要安全检查,可直接放访问24        field.set(u3, "jzman");//反射设置User对象的name属性值25        System.out.println("u3:"+u3);26        System.out.println("获取User对象u3的name属性值:"+field.get(u3));2728        //反射操作类的方法29        System.out.println("----------反射操作类的方法----------");30        User u4 = c1.newInstance();31        Method method = clazz.getDeclaredMethod("setPassword", String.class);32        method.invoke(u4, "222222");//设置User对象u4的password属性,等同于u4.setPassword("222222);33        System.out.println("u4:"+u4);3435    } catch (Exception e) {36        e.printStackTrace();37    }38}
上述代码的执行结果如下:
1----------反射操作类的构造方法----------2u1:User [id=0, name=null, password=null]3u2:User [id=1000, name=jzman-blog, password=111111]4----------反射操作类的属性----------5u3:User [id=0, name=jzman, password=null]6获取User对象u3的name属性值:jzman7----------反射操作类的方法----------8u4:User [id=0, name=null, password=222222]
实际开发中肯定会遇到某个组件中需要某个属性,但是该属性又是私有的,这时候就可以使用 Java 的反射机制了。
反射操作泛型
Java 采用泛型擦除的机制,Java 中的泛型仅仅是给编译器 javac 使用的,这样可确保数据的安全性的免去强制类型转换的麻烦,当编译完成之后,所有和泛型相关的类型将会被全部擦除,为了能够使用反射操作这些类型,新增了四种类型 GenericArrayType、ParameterizedType、TypeVariable 和 WildcardType 来表示不能被归一到 Class 类中的类型但又是和原始类型齐名的类型,也就是说正常的能够获取对应的 Class 对象的 Type 还是 Class 对象,如基本数据类型。反射操作泛型就要涉及到 Java 中的 Type, 在 Java 中 Type 表示所有类型的公共接口,这些类型包括原始类型、参数化类型、数组类型、类型变量和基本类型,其声明如下:
1/**2 * Type 是 Java 语言中所有类型的公共接口3 * 这些类型包括原始类型、参数化类型、数组类型、类型变量和基本类型4 */5public interface Type {6    default String getTypeName() {7        return toString();8    }9}
Type 有四个直接子接口,具体含义如下:
1GenericArrayType:表示泛型数组类型,如 ArraryList[] listArrary2ParameterizedType:表示参数化类型(泛型),如 ArrayList list3TypeVariable:表示类型变量,如T4WildcardType:表示一个通配符类型,如 ?、? extends Number 或 ? super Integer
下面以 GenericArrayType 和 ParameterizedType  为例来说明如何使用反射来操作泛型类型,具体如下:
 1//用来测试获取泛型的属性 2private String[] array; 3private List[] listArray; 4//用来测试获取泛型的方法 5private String testGenericType(Map map, String[] array, int name,User user) { 6    System.out.println("testGenericType"); 7    return null; 8} 910//通过反射获取泛型11private static void refectGenericType() {12    try {       13        System.out.println("---------GenericArrayType---------");1415        //获取泛型数组(GenericArrayType)16        Field field = ReflectTest02.class.getDeclaredField("listArray");//获取属性listArray17        GenericArrayType type = (GenericArrayType) field.getGenericType();18        System.out.println("获取泛型数组:"+type);1920        System.out.println("---------ParameterizedType---------");2122        //获取参数化类型(泛型)(ParameterizedType)23        Method method = ReflectTest02.class.getDeclaredMethod("testGenericType", Map.class,String[].class,int.class,User.class);24        Type[] types = method.getGenericParameterTypes();//获得方法参数类型25        for(Type type1: types) {26            System.out.println("方法参数类型:"+type1);27            if(type1 instanceof ParameterizedType) {28                System.out.println("ParameterizedType:"+type1);29            }30        }3132    } catch (Exception e) {33        e.printStackTrace();34    }35}
上述代码中方法 refectGenericType 的执行结果如下:
1---------GenericArrayType---------2获取泛型数组:java.util.List[]3---------ParameterizedType---------4方法参数类型:java.util.Map5ParameterizedType:java.util.Map6方法参数类型:class [Ljava.lang.String;7方法参数类型:int8方法参数类型:class com.manu.reflection.bean.User9
可参照代码查看对应的输出结果。
反射获取注解信息
通过反射还可以获取注解信息,记如果对注解比较陌生可以参考之前分享的一篇文章 Java 系列之注解,这里简单模仿数据库表字段与 Java 对象的属性是如何通过注解信息一一对应的,为什么我们使用一些数据库框架的时候,通过一些表注解、字段注解就能够创建表,这里就涉及到使用反射来获取注解信息来生成 SQL,进而生成对应的表。创建两个注解分别作为表注解和字段注解,参考如下:
 1//表注解 2@Target(ElementType.TYPE) 3@Retention(RetentionPolicy.RUNTIME) 4public @interface TableAnnotation { 5    String value(); 6} 7 8//字段注解 9@Target(ElementType.FIELD)10@Retention(RetentionPolicy.RUNTIME)11public @interface FieldAnnotation {12    String column();13    int length();14    String type();15}
然后,创建一个类并使用该注解,参考如下:
 1/** 2 * 反射读取注解信息测试Bean 3 * @author jzman 4 */ 5 6@TableAnnotation(value = "student_table") 7public class Student { 8    @FieldAnnotation(column = "uid", length = 20, type = "int") 9    private int sId;10    @FieldAnnotation(column = "name", length = 10, type = "varchar")11    private String sName;12    @FieldAnnotation(column = "uiaged", length = 3, type = "varchar")13    private int sAge;1415    //setter、getter方法16    //...17}
最后,获取注解信息,参考如下:
 1/** 2 * 反射获取注解信息 3 * @author jzman 4 */ 5public class ReflectTest03 { 6    public static void main(String[] args) { 7        try { 8            Class clazz = Class.forName("com.manu.reflection.bean.Student"); 910            //反射获取类的注解信息11            TableAnnotation tableAnnotation = (TableAnnotation) clazz.getAnnotation(TableAnnotation.class);12            System.out.println("反射获取类的注解信息:"+tableAnnotation);1314            //反射获取属性的注解信息15            Field field = clazz.getDeclaredField("sName");16            FieldAnnotation fieldAnnotation = field.getAnnotation(FieldAnnotation.class);17            System.out.println("反射获取属性的注解信息:"+fieldAnnotation);1819            //获取其他注解信息使用方式类似20            //...21        } catch (Exception e) {22            e.printStackTrace();23        }24    }25}
上述代码的执行结果如下:
1反射获取类的注解信息:@com.manu.reflection.TableAnnotation(value=student_table)2反射获取属性的注解信息:@com.manu.reflection.FieldAnnotation(column=name, length=10, type=varchar)
显然,通过反射获取到了相应的注解信息,这些注解信息标注了该类对应数据库表的一些关键信息,然后就可以生成对应的 SQL 语句,这样就不难理解数据库表字段与Java对象属性的映射关系了。使用反射获取私有属性或私有方法是必须设置 setAccessible 为 true 才能跳过 Java 安全检查,从而获取私有的属性、方法等,同时设置 setAccessible 为 true 在一定程度上可以提高反射的运行速度。 推荐阅读:
  • Platform Channel使用详解

  • 了解一下基金的风险

  • 编译时注解详解及实现ButterKnife
0bf5d4c2f28f60cf29a4438d76a246dc.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值