所使用的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 是一个类, 位于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 对象表示的字段设置为指定的新值
所使用的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 的类型不一致就会导致类型转换异常(反射获取或者修改一个变量的值时, 编译器不会再自动拆装箱, 一些类型转换需要自己手动完成)
1.Method和Field、Constructor对象都有setAccessible()方法。 2.setAccessible作用是 启动和禁用访问安全检查的开关。 3参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。 (1)提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true。 (2)使得原本无法访问的私有成员也可以访问 4.参数值为false则指示反射的对象应该实施Java语言访问检查