如何利用反射获取对象并利用field去修改属性

    科技2024-07-07  71

    一、如何利用反射获取对象

    所使用的pojo:

    public class Person { private String name; private static int age = 58; public Person() { System.out.println("Person的无参构造器"); } public Person(String name) { this.name = name; System.out.println("Person的有参构造器"); } }//提供get和set方法 public class Student extends Person { public Student() { System.out.println("Student的无参构造器"); this.setName("学生"); } }

    测试代码:

    public static void main(String[] args) throws ClassNotFoundException { Person person = new Student(); System.out.println("这个人是:" + person); //方式一:通过对象获得 Class c1 = person.getClass(); System.out.println(c1); System.out.println(c1.hashCode()); //方式二:通过forName获得 Class c2 = Class.forName("com.mi.pojo.Student"); System.out.println(c2); System.out.println(c2.hashCode()); //方式三:通过类名.class获得 Class c3 = Student.class; System.out.println(c3); System.out.println(c3.hashCode()); //获得父类类型 Class superclass = c3.getSuperclass(); System.out.println(superclass); System.out.println(superclass.hashCode()); }

    测试结果:

    通过三种方式获取的对象的hashcode值都相同,也说明了一个类只有一个Class对象

    如何利用反射创建一个新的对象呢?

    可以利用

    class.newInstance();

    测试代码:

    Class c3 = Student.class; System.out.println(c3); System.out.println(c3.hashCode()); Object c6 = c3.newInstance(); System.out.println(c6); System.out.println(c6.getClass().hashCode()); System.out.println(person.hashCode()); System.out.println(c6.hashCode());

    测试结果:

    c6是利用newInstance()创建的对象,也说明了利用newInstance()创建的对象是调用无参构造器,也可以利用有参构造器创建对象,首先Class.getDeclaredConstructor()去获取一个有参构造器,再调用newInstance()设置对应的参数进行创建对象

    Constructor<Person> constructor = c5.getDeclaredConstructor(String.class); Person person1 = constructor.newInstance("芈");

    person和c6有着不同的hashcode值,这就说明了c6是一个新的对象,而不是之前的对象。在利用newInstance()创建的对象时,调用的无参构造器进行创建新的对象。c3是person的Class对象,打印出来的c6的Class对象的hashcode和c3打印的hashcode是相同的,也说明了一个类只有一个Class对象

    二、如何利用field修改属性值

    Field 是一个类, 位于java.lang.reflect包下。 在java 的反射中field 类描述的是类的属性信息,功能包括:

     1: 获取当前对象的成员变量的类型

     2: 对成员变量重新设置值

     

     四种方法获取到Field 类对象

      1: Class.getFields()   获取类中public类型的属性, 返回一个包含某些field对象的数组, 该数组包含此Class对象所表示的类或接口的所有可访问公共字段

      2: Class.getDeclaredFields()   获取类中所有属性(public protect default private) , 但是不包括继承的属性, 返回field对象的一个数组

      3: Class.getField(String name) 获取类特定的方法,name 参数指定了属性的名称

      4: Class.getDeclaredField(String name)  获取类特定的方法, name 参数指定了属性的名称

    注意:与属性对应的还有方法和构造器,方法:Class.getMethods();Class.getMehod();Class.getDeclaredMethods();Class.getDeclaredMethod(),在获取到方法后,要配合invoke(对象,参数值)使用,如果属性为private,同样也要使用field.setAccessible() 方法将参数设置为true;构造器:Class.getConstructors();Class.getConstructor();Class.getDeclaredConstructors();Class.getDeclaredConstructor(),在获取到构造器后,要配合newInstance()方法使用,如果构造器为private,同样也要使用field.setAccessible() 方法将参数设置为true

    Field 对象常用方法

      获取变量的类型

      Field.getType():  返回这个变量的类型

      Field.getGenericType: 如果当前属性有签名属性类型就返回, 否则就返回 Field.getType()

      isEnumConstant(): 判断这个属性是否是枚举类

      获取成员变量的修饰符

           Field.getModifiers() 以整数形式返回此 Field 对象标识的字段的java 语言修饰符

      获取和修改成员变量的值

      getName():  获取属性的名字

      get(Object obj): 返回指定对象obj上此field表示的字段值

      set(Object obj, Object value) 将指定对象变量上此field 对象表示的字段设置为指定的新值

     

    如何使用Field 呢?

    所使用的pojo仍为上面所用的例子

    1.先在方法区创建一个Class对象

    2.利用反射获取该对象(上面所写的三种方法都可以获取,测试用类名.class的方式反射获取对象)

    3.获取到对应属性的Field(利用getDeclaredField)

    4.使用field.setAccessible() 方法将参数设置为true(因为set(Object obj, Object value)时, 修改final类型的变量导致的类型转换异常。由于Field继承自AccessibleObject,我们可以使用AccessibleObject.setAccessible() 方法告诉安全机制,这个变量可以访问)

    5.利用field.set(Object obj, Object value)进行属性修改

    测试代码:

    Person person = new Person(); Class<Person> c5 = Person.class; Field field = c5.getDeclaredField("age");//private static int age = 58; field.setAccessible(true); System.out.println(field);//当前field就是所要修改的属性 System.out.println(field.getName());//field.getName可以获取属性的名字 System.out.println(field.getType());//field.getType可以获取属性的类型 System.out.println(field.toString());//field.toString就是所要修改的属性 System.out.println(person.getAge());//先看看修改前的属性值 System.out.println(field.get("age"));//field.get("XXX")可以获取属性的内容 field.set(person,30);//field.set(Object obj, Object value)进行属性修改 System.out.println(field.get("age"));//查看属性是否修改 System.out.println(person.getAge());//查看属性是否修改

    测试结果:

    Field可以修改所有的属性,测试所用的age为private、static类型,但利用Field进行修改属性值时,如果新value 和原 value 的类型不一致就会导致类型转换异常(反射获取或者修改一个变量的值时, 编译器不会再自动拆装箱, 一些类型转换需要自己手动完成)

    什么是setAccessible方法?

    1.Method和Field、Constructor对象都有setAccessible()方法。 2.setAccessible作用是 启动和禁用访问安全检查的开关。 3参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。 (1)提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true。 (2)使得原本无法访问的私有成员也可以访问 4.参数值为false则指示反射的对象应该实施Java语言访问检查  

     

     

    Processed: 0.009, SQL: 9