1.反射概述
1.1 反射引入
1.3 Java反射的作用
1.4 Java反射相关的类
2.Class类的使用
-
回忆一下之前如何使用一个Java类?
-
已知一个类的类名、以及类中的方法、属性、构造方法等
-
调用构造方法创建对象
-
使用对象调用方法或属性
-
-
问题:
-
如果仅仅知道一个类的类名,能否动态得到类的定义信息,包括哪些方法,属性等?
-
-
答案:可以通过反射做到
-
1.2 Java反射的概念
-
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取信息以及动态调用对象的方法的功能称为java语言的反射机制。
-
如果做到的呢?
当一个字节码文件加载到内存的时候,jvm会对该字节码进行解剖,然后创建一个对象的Class对象,把字节码文件的信息全部都存储到该Class对象中,我们只要获取到Class对象,我们就可以使用字节码对象设置对象的属性或者调用对象的方法等操作。
-
动态获取类的信息,进一步实现需要的功能
-
Java反射相关的类主要包括
-
Class 类型
-
Constructor 构造方法
-
Method 方法
-
Field 属性
-
……
-
除了Class外,其他类都位于java.lang.reflect包中
-
-
可见,反射API将类的类型、方法、属性都封装成了类
-
其中最重要的类是Class,可以说,反射的使用都是从Class开始
-
例如:Spring框架通过XML文件描述类的基本信息,使用反射机制动态装配对象
-
如何获得Class实例?为一个class生成对应的Class对象
-
案例:
package reflect;
public class Person {
public String puEmail;
private String name11;
private int age;
//私有构造方法
private Person(int age,String name){
this.age=age;
this.name11=name;
}
public Person() {
}
public Person(int age) {
this.age = age;
}
public Person(String name) {
this.name11 = name;
}
public Person(String name, int age) {
this.name11 = name;
this.age = age;
}
public Person(String puEmail, String name) {
this.puEmail = puEmail;
this.name11 = name;
}
public Person(String puEmail, String name, int age) {
this.puEmail = puEmail;
this.name11 = name;
this.age = age;
}
public String getName() {
return name11;
}
public void setName(String name) {
this.name11 = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void sayHello(){
System.out.println("你好");
}
public void sayHello(String str){
System.out.println("sayHello方法被调用了,传入的参数是:"+str);
}
private void my(){
System.out.println("my");
}
private void my(Integer i){
System.out.println("Integer");
}
private void my(int i){
System.out.println("Integer");
}
protected void myProtected(){
System.out.println("myProtected");
}
void myDefault(){
System.out.println("myDefault");
}
@Override
public String toString() {
return "Person{" +
"puEmail='" + puEmail + '\'' +
", name='" + name11 + '\'' +
", age=" + age +
'}';
}
private double add(int a,Double b){
return a+b;
}
public int getScore(){
return 11;
}
}
Class类是Java反射机制的基础,通过Class类,可以得到一个类的基本信息。以下类是Class类的常用方法:
案例:
package reflect;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
public class ClassTest {
public static void main(String[] args) {
Class personClazz=Person.class;
System.out.println("=============Fields");
//Fields
Field[] fields=personClazz.getFields();
System.out.println(fields.getClass());
//获取定义公有的字段
System.out.println("=============getFields");
for(Field field:fields){
System.out.println(field.getName());
}
System.out.println("===========getDeclaredFields========");
//获取定义的所有的字段
Field[] declaredFields=personClazz.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField.getName());
}
System.out.println("===========getField(String)==========");
try {
//getField获取指定的(成员变量)公有字段
Field nameField=personClazz.getField("puEmail");
System.out.println(nameField);
} catch (NoSuchFieldException e) {
//NoSuchFieldException 未找到对应字段
e.printStackTrace();
}
System.out.println("===========getDeclaredField(String)========");
try {
//getDeclaredField获取定义指定(根据成员变量名称)的成员变量
Field nameField=personClazz.getDeclaredField("name11");
System.out.println(nameField);
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
//getMethod获取公有的方法(包括父类)
System.out.println("============getMethods=================");
Method[] pubilcMethods=personClazz.getMethods();
for (Method publicMethod : pubilcMethods) {
System.out.println(publicMethod);
}
//getDeclaredMethods获取自定义的方法
System.out.println("============getDeclaredMethods=================");
Method[] declaredMethods=personClazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println("============getMethods(String)=================");
try {
//获取无参的Method对象
Method sayHello1=personClazz.getMethod("sayHello");
System.out.println(sayHello1);
//获取有参的Method对象
Method sayHello2=personClazz.getMethod("sayHello",String.class);
System.out.println(sayHello2);
Method wait=personClazz.getMethod("wait");
System.out.println(wait);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//根据方法名称和参赛列表 获取定义的方法
System.out.println("============getDeclaredMethod(Integer)=================");
try {
Method my=personClazz.getDeclaredMethod("my");
System.out.println(my);
Method my1=personClazz.getDeclaredMethod("my",Integer.class);
System.out.println(my1);
Method my2=personClazz.getDeclaredMethod("my",int.class);
System.out.println(my2);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//public的构造方法
System.out.println("===========getConstructors()============");
Constructor[] publicConstructors=personClazz.getConstructors();
for (Constructor publicConstructor : publicConstructors) {
System.out.println(publicConstructor);
}
//获取定义的构造方法
System.out.println("===========getDeclaredConstructors()============");
Constructor[] declaredConstructors=personClazz.getDeclaredConstructors();
for (Constructor declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
//根据参数列表类型还有顺序获取public定义构造方法
System.out.println("===========getConstructor()============");
try {
Constructor publicConstructor = personClazz.getConstructor(String.class,String.class);
System.out.println(publicConstructor);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//根据参数列表类型还有顺序获取定义构造方法
System.out.println("===========getDeclaredConstructor()============");
try {
Constructor declaredConstructor=personClazz.getDeclaredConstructor(int.class,String.class);
System.out.println(declaredConstructor);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
System.out.println("============getName getPackage=======");
System.out.println(personClazz.getName());
System.out.println(personClazz.getPackage());
System.out.println("=================new 类名称===============");
Person p=new Person();
Person p1=new Person("jack");
System.out.println(p);
System.out.println(p1);
System.out.println("==============newInstance=============");
try {
//newInstance方法创建实例对象(Class 类型对应的类对象)
// personClazz.newInstance() 创建Person对象过程中,调用无参的构造方法
Person person=(Person)personClazz.newInstance();
System.out.println(person);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
3.Constructor类的使用
-
获取Constructor类的实例方式:
-
Constructor<T> getConstructor(Class... parameterTypes) :通过指定参数类型,返回构造方法实例
-
Constructor[] getConstructors() :返回该类的所有构造方法实例
-
-
Constructor类可以通过getXXX方法获得构造方法的基本信息,例如:
-
String getName:返回构造方法的名字
-
Class<>[] getParameterTypes:返回构造方法的参数类型
-
-
除了获得构造方法的基本信息,还可以创建实例
-
Object newInstance(Object... initargs) :创建实例
-
案例:
package reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ConstructorTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class personClazz = Class.forName("reflect.Person");
//获取所有的构造方法
Constructor[] declareConstructors = personClazz.getDeclaredConstructors();
// Constructor[] c=personClazz.getDeclaredConstructors();
// for (Constructor constructor : c) {
// System.out.println(constructor);
// }
for (Constructor declareConstructor : declareConstructors) {
Person p = null;
//获取构造方法数量
int parameterCount = declareConstructor.getParameterCount();
switch (parameterCount) {
case 0: {
p = (Person) (declareConstructor.newInstance());
System.out.println("构造方法0个参数,创建Person:" + p);
break;
}
case 1: {
//获取构造方法的参数类型列表
Class[] parameterTypes = declareConstructor.getParameterTypes();
if (parameterTypes[0].equals(String.class)) { //如果构造方法的参数时String类型的
// declareConstructor.newInstance()创建实例对象
p = (Person) declareConstructor.newInstance("jack");
System.out.println("构造方法1个参数String类型,创建Person:" + p);
} else if (parameterTypes[0].equals(int.class)) {
p = (Person) declareConstructor.newInstance(20);
System.out.println("构造方法1个参数int类型,创建Person:" + p);
} else {
System.out.println("构造方法1参数其他参数暂不处理");
}
break;
}
case 2: {
//获取构造方法的参数类型列表
Class[] parameterTypes = declareConstructor.getParameterTypes();
if (parameterTypes[0].equals(int.class) && parameterTypes[1].equals(String.class)) {
//私有的构造方法,不能使用Constructor的newInstance
//isAccessible判断构造方法是否反射调用
// setAccessible传入true参数可以让私有的构造方法,可以反射调用
// 如果不设置setAccessible参数为true,私有的构造方法不能反射调用
declareConstructor.setAccessible(true);
p = (Person) declareConstructor.newInstance(30, "jim");
System.out.println("构造方法2个参数,第一是int类型,第二个是String,创建Person对象" + p);
} else if (parameterTypes[0].equals(String.class) && parameterTypes[1].equals(String.class)) {
// declareConstructor.newInstance()创建实例对象
p = (Person) declareConstructor.newInstance("AA@1776.com", "jiwwwm");
System.out.println("构造方法2个参数,第一是String类型,第二个是String,创建Person对象" + p);
} else if (parameterTypes[0].equals(String.class) && parameterTypes[1].equals(int.class)) {
p = (Person) declareConstructor.newInstance("laowang", 90);
System.out.println("构造方法2个参数,第一是String类型,第二个是int,创建Person对象" + p);
} else {
System.out.println("构造方法2参数其他参数暂不处理");
}
break;
}
case 3: {
//获取构造方法的参数类型列表
Class[] parameterTypes = declareConstructor.getParameterTypes();
if (parameterTypes[0].equals(String.class) && parameterTypes[1].equals(String.class) &&
parameterTypes[2].equals(int.class)) {
// declareConstructor.newInstance()创建实例对象
p = (Person) declareConstructor.newInstance("mmm@qq.com", "laoli", 90);
System.out.println("构造方法3个参数,第一是String类型,第二个是String,第三个参数int,创建Person对象" + p);
} else {
System.out.println("构造方法3参数其他参数暂不处理");
}
break;
}
default: {
System.out.println("构造方法参数数量大于3,不处理");
}
}
}
}
}
4.Method类的使用
-
获取Method实例的方式:
-
Method getMethod(String name, Class... parameterTypes) :通过指定方法名,参数类型,返回一个Method实例
-
Method[] getMethods() :返回该类中所有方法的Method实例
-
-
Method类将类中的方法进行封装,可以动态获得方法的信息,例如
-
getReturnType:获得方法返回值类型
-
getName:获得方法名字
-
getParameterTypes:获得方法参数类型
-
-
除了动态获得方法信息外,Method还能动态调用某一个对象的具体方法
-
Object invoke(Object obj, Object... args) :使用obj调用该方法,参数为args
-
案例:
package reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodTest {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//获取Person的Class类型对象
Class<Person> personClazz=Person.class;
//获取到Person对应Method对象(方法对象)
//获取sayHello方法,参数为一个,是String类型
Method sayHelloMethod=personClazz.getMethod("sayHello",String.class);
//反射的方式创建Person对象(Class类的对象newInstance方法创建Person对象)
Object p=personClazz.newInstance();
//反射调用对应方法
//Method invoke方法的第一个参数是Method对应的类的实例对象(以Person的sayHello为例子
// sayHelloMethod理解成sayHello方法,第一个参数是Person的对象
//第二个参数是实参
//invoke返回值,表示调用sayHello的返回值(以Person的sayHello为例子,返回值,是调用sayHello返回值结果)
Object returnResult=sayHelloMethod.invoke(p,"哈哈哈");
System.out.println(returnResult);
System.out.println("=========反射调用Person对象的方法=======");
//获取add方法
//getMethod获取public方法,add方法是私有的获取不到
// Method addMethod=personClazz.getMethod("add",int.class,Double.class);
// getDeclaredMethod获取所有定义的方法
Method addMethod=personClazz.getDeclaredMethod("add",int.class,Double.class);
// 私有的方法反射触发调用
addMethod.setAccessible(true);
//invoke触发方法
Object addReturnResult=addMethod.invoke(p,20,30.0);
System.out.println(addReturnResult);//返回值
System.out.println(addMethod.getName());//方法名
System.out.println(addMethod.getReturnType());//返回值类型
Class<?>[] addParameterTypes = addMethod.getParameterTypes();
for (Class<?> addParameterType : addParameterTypes) {
System.out.println(addParameterType);
}//参数类型
System.out.println(addMethod.getParameterCount());//参数个数
}
}
5.Field类的使用
-
获得Field实例,都是通过Class中的方法实现
-
public Field getField(String name)
-
通过指定Field名字,返回Field实例
-
注意Field的访问权限 (一定是public)
-
-
Field类将类的属性进行封装,可以获得属性的基本信息、属性的值,也可以对属性进行赋值
-
getName:返回属性的名字
-
getXXX:例如,getFloat返回该属性float类型的值
-
setXXX:例如,setFloat为属性赋值float类型的值
-
案例 :
package reflect;
import java.lang.reflect.Field;
public class FieldTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException {
//Person的Class对象
Class personClazz =Class.forName("reflect.Person");
//获取指定的成员变量的Field对象
Field puEmailField=personClazz.getField("puEmail");
//反射创建Person对象
Object p=personClazz.newInstance();
System.out.println("使用无参构造方法创建对象p:"+p);
//puEmailField对象对应的字段值设置值
//第一个参数成员变量对象对应类的对象类型
puEmailField.set(p,"15615625561@.com");
System.out.println("对象p的puEmail成员变量设置值之后对象p:"+p);
System.out.println("puEmail值为"+puEmailField.get(p));
//getDeclareField所有的定义的成员变量
Field nameField = personClazz.getDeclaredField("name11");
nameField.setAccessible(true);
//set没有调用Person的setName方法,直接通过反射给name成员变量赋值
nameField.set(p,"jack");
System.out.println("对象p的name成员变量设置值之后对象p:"+p);
}
}