本文主要介绍
1、反射的概念和原理
2、反射的源头Class类
3、利用反射操作类的属性(以及如何获取私有属性)
4、利用反射操作类的构造方法(以及私有构造方法)
5、利用反射操作类的方法(以及私有方法)
1、反射的概念和原理
要想理解反射的原理,首先要了解什么是类型信息。Java让我们在运行时识别对象和类的信息,主要有2种方式:一种是传统的RTTI,它假定我们在编译时已经知道了所有的类型信息;另一种是反射机制,它允许我们在运行时发现和使用类的信息。
反射是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法.这种动态获取信息,以及动态调用对象方法的功能叫java语言的反射机制.
2、反射的源头Class类
package com.myday02.bean;
public class Person {
public String name;
public int age;
public String sex;
private String adress;
private String money;
public String getAdress() {
return adress;
}
private void setAdress(String adress) {
this.adress = adress;
}
public String getMoney() {
return money;
}
private void setMoney(String money) {
this.money = money;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
private Person(String name, int age, String sex, String adress, String money) {
super();
this.name = name;
this.age = age;
this.sex = sex;
this.adress = adress;
this.money = money;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
}
获取Classl类的3种方式
(1)通过Objeck类中的getClass()方法获取
//实例化对象
Person person = new Person("张三",22);
//获取对象所在类信息
Class personClass = person.getClass();
(2)通过类.class获取
Class personClass = Person.class
(3)通过Class类的forName()方法获取
Class personClass = Class.forName("com.myday02.bean.Person");
通过forName()获取到Class对象后可以调用newInstance()方法创建此Class对象所表示的新实例(需要注意的是使用newInstance()方法创建对象实例化程序默认调用的是无参构造方法,所以我们在定义类的时候要保留无参的构造方法,不然会出现InstantiationException
异常,而且无参构造方法不能设置为私有,不然会出现IllegalAccessException
异常)。
//通过类信息创建对象,使用无参构造方法实例化
Person p = (Person) personClass.newInstance();
3、利用反射操作类的属性(以及如何获取私有属性)
(1)获取类所有公共属性
通过调用Class类的getFields()
方法获取
Field[] | getFields() 返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。 |
例如
//获取Class对象所表示的类或接口的所有可访问公共字段
Field[] fields = personClass.getFields();
for (Field fds : fields) {
System.out.println("属性名称:"+fds.getName()+"\t属性类型:"+fds.getType());
}
输出
属性名称:name 属性类型:class java.lang.String
属性名称:age 属性类型:int
属性名称:sex 属性类型:class java.lang.String
(2)获取类指定公共属性
通过调用Class类的getField(String name)
方法获取,并可以使用Filed类的set方法设置属性值
Field | getField(String name) 返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。 |
例如
//通过Class类访问指定公共属性,并设置属性值
Field field = personClass.getField("name");
field.set(person,"李四");
System.out.println(field.get(person));
System.out.println(person.getName());
输出
李四
李四
(3)获取类所有属性(包括私有属性)
通过调用Class类的getDeclaredFields()
方法获取
Field[] | getDeclaredFields() 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。 |
例如
//获取Class 对象所表示的类或接口所声明的所有字段。包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段
Field[] fields = personClass.getDeclaredFields();
for (Field fds : fields) {
System.out.println("属性名称:"+fds.getName()+"\t属性类型:"+fds.getType());
}
输出
属性名称:name 属性类型:class java.lang.String
属性名称:age 属性类型:int
属性名称:sex 属性类型:class java.lang.String
属性名称:adress 属性类型:class java.lang.String
属性名称:money 属性类型:class java.lang.String
(4)获取类指定所有属性(包括私有属性)
通过调用Class类的getDeclaredField(String name)
方法获取
Field | getDeclaredField(String name) 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。 |
由于属性是私有的,所以想要使用Filed类的set()方法进行设置属性值,需要先调用setAccessible(AccessibleObject[] array, boolean flag)
方法,并将其设置为true
static void | setAccessible(AccessibleObject[] array, boolean flag) 设置为true时,表示运行时忽略访问修饰符,false时,表示运行析访问修饰符生效 |
所以setAccessible(true)表示运行时忽略访问修饰符
这样便可以设置私有属性值了
例如
Field field = personClass.getDeclaredField("address");
field.setAccessible(true); //运行时忽略访问修饰符
field.set(person,"中国");
System.out.println(field.get(person));
System.out.println(person.getName());
输出
中国
中国
4、利用反射操作类的构造方法
java.lang.reflect
类 Constructor<T>
java.lang.Object java.lang.reflect.AccessibleObject java.lang.reflect.Constructor<T>
类型参数:
T
- 在其中声明构造方法的类。
所有已实现的接口:
AnnotatedElement, GenericDeclaration, Member
(1)获取类所有公共构造方法
通过调用Class类的getConstructors()
方法获取
Constructor<?>[] | getConstructors() 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。 |
例如
//获取类所有公共构造方法
Constructor[] css = personClass.getConstructors();
for (int i = 0; i < css.length; i++) {
System.out.println(css[i].toString());
}
输出
public com.myday02.bean.Person()
public com.myday02.bean.Person(java.lang.String,int)
(2)获取类所有构造方法
通过调用Class类的getDeclaredConstructors()
方法获取
Constructor<?>[] | getDeclaredConstructors() 返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。 |
//获取所有构造方法
Constructor[] css = personClass.getDeclaredConstructors();
for (int i = 0; i < css.length; i++) {
System.out.println(css[i].toString());
}
输出
private com.qf.myday02.bean.Person(java.lang.String,int,java.lang.String,java.lang.String,java.lang.String)
public com.qf.myday02.bean.Person(java.lang.String,int)
public com.qf.myday02.bean.Person()
(3)获取类指定的公共带参构造方法
通过调用Class类的getConstructor(Class<?>... parameterTypes)
方法获取
Constructor<T> | getConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。 |
例如
//获取指定的公共带参构造方法
Constructor cs = personClass.getConstructor(String.class,int.class);
Person ps = (Person) cs.newInstance("李四",20);
System.out.println(ps.toString());
输出
Person [name=李四, age=20]
(4)获取类指定的带参构造方法
通过调用Class类的getDeclaredConstructor(Class<?>... parameterTypes)
方法获取
Constructor<T> | getDeclaredConstructor(Class<?>... parameterTypes) 返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。 |
由于需要调用私有的带参构造方法初始化对象,同上需要忽略访问修饰符,即将setAccessible(AccessibleObject[] array, boolean flag)方法设置为
true。
例如
//获取指定的带参构造方法
Constructor cs = personClass.getDeclaredConstructor(String.class,int.class,String.class,String.class,String.class);
cs.setAccessible(true);
Person ps = (Person) cs.newInstance("李四",20,"男","中国","一亿");
System.out.println(ps.toString());
输出
Person [name=李四, age=20, sex=男, adress=中国, money=一亿]
5、利用反射操作类的方法(以及私有方法)
(1)获取类的指定公共方法
通过调用Class类的getMethod(String name, Class<?>... parameterTypes)
方法获取
Method | getMethod(String name, Class<?>... parameterTypes) 返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。 |
Object | invoke(Object obj, Object... args) 对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。 |
例如
Method method0 = personClass.getMethod("setAge", int.class);
method0.invoke(person, 10);
System.out.println(p.toString());
输出
Person [name=null, age=10, sex=null, adress=null, money=null]
(2)获取类的指定方法
通过调用Class类的getDeclaredMethod(String name, Class<?>... parameterTypes)
方法获取
Method | getDeclaredMethod(String name, Class<?>... parameterTypes) 返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。 |
例子
Method method0 = personClass.getDeclaredMethod("setMoney", String.class);
method0.setAccessible(true);
method0.invoke(person, "十亿");
System.out.println(p.toString());
输出
Person [name=null, age=0, sex=null, adress=十亿, money=null]
(3)获取类的所有公共方法(包括继承的方法)
通过调用Class类的getMethods()
方法获取
Method[] | getMethods() 返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。 |
例如
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
输出
toString
getName
setName
setAge
getAdress
getMoney
getSex
setSex
getAge
wait
wait
wait
equals
hashCode
getClass
notify
notifyAll
Person
(4)获取类的所有方法(不包括继承的方法)
通过调用Class类的getDeclaredMethods()
方法获取
Method[] | getDeclaredMethods() 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。 |
例如
Method[] methods = personClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
输出
toString
getName
setName
setMoney
setAge
getAdress
setAdress
getMoney
getSex
setSex
getAge
Person
总结:上面的只是对反射的一些常用方法介绍,通过上面可以发现我们在访问私有属性,私有方法时都可以通过将setAccessible(AccessibleObject[] array, boolean flag)方法设置为
true忽略其访问修饰,来成功操作。
更多方法可以参考JDK文档学习。