有没有听说反射是Java中最强大的技术,很多优秀的开源框架都是通过反射完成的,那么你学会反射了吗?
JAVA反射机制概述
平常我们想调一个类中的方法时,类中用private修饰的变量、方法我们都调用不了,但是反射可以。
Reflection(反射)是被视为动态语言
的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
首先了解下什么是动态语言
-
动态语言
是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运 行时代码可以根据某些条件改变自身结构
-
静态语言
与动态语言相对应的,运行时结构不可变的语言就是静态语言。
Java不是动态语言,Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。
反射机制的概念
指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法.这种动态获取信息,以及动态调用对象方法的功能叫java语言的反射机制。
反射相关的主要API
- java.lang.Class:代表一个类
- java.lang.reflect.Method:代表类的方法
- java.lang.reflect.Field:代表类的成员变量(类的属性)
- java.lang.reflect.Constructor:代表类的构造方法
Class类的常用方法
ClassLoader | getClassLoader() | 返回类的类加载器。 |
---|---|---|
static class<?> | forName(String className) | 返回与给定字符串名称的类或接口相关联的 类 对象。 |
Annotation[] | getAnnotations() | 返回此元素上 存在的注释。 |
ClassLoader | getClassLoader() | 返回类的类加载器。 |
Constructor<T> | getConstructor(class<?>... parameterTypes) | 返回一个 Constructor 对象,该对象反映 Constructor 对象表示的类的指定的公共 类 函数。 |
Constructor<?>[] | getConstructors() | 返回包含一个数组 Constructor 对象反射由此表示的类的所有公共构造 类 对象。 |
Constructor<T> | getDeclaredConstructor(类<?>... parameterTypes) | 返回一个 Constructor 对象,该对象反映 Constructor 对象表示的类或接口的指定 类 函数。 |
Constructor<?>[] | getDeclaredConstructors() | 返回一个反映 Constructor 对象表示的类声明的所有 Constructor 对象的数组 类 。 |
Field | getDeclaredField(String name) | 返回一个指定的运行时类中指定变量名的Field 对象,包括公共,保护,默认访问和私有属性 |
Field[] | getDeclaredFields() | 返回的数组 Field 对象反映此表示的类或接口声明的所有字段 类 对象。 |
Method | getDeclaredMethod(String name, 类<?>... parameterTypes) | 返回一个指定的 方法 对象。参数(获取方法的名称,获取方法的形参列表) |
Method[] | getDeclaredMethods() | 返回包含一个数组 方法 对象反射的类或接口的所有声明的方法,通过此表示 类 对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。 |
Field | getField(String name) | 返回一个指定的运行时类中公共的指定变量名的Field 对象 |
Field[] | getFields() | 返回包含一个数组 Field 对象反射由此表示的类或接口的所有可访问的公共字段 类 对象。 |
String | getName() | 返回由 类 对象表示的实体(类,接口,数组类,原始类型或空白)的名称,作为 String 。 |
int | getModifiers() | 返回此类或接口的Java语言修饰符,以整数编码。(0-default、1-public、2-private ) |
String | getTypeName() | 为此类型的名称返回一个内容丰富的字符串。 |
class<?>[] | getInterfaces() | 确定由该对象表示的类或接口实现的接口。 |
Method | getMethod(String name, class<?>... parameterTypes) | 返回一个 方法 对象,它反映此表示的类或接口的指定公共成员方法 类 对象。 |
Method[] | getMethods() | 返回包含一个数组 方法 对象反射由此表示的类或接口的所有公共方法 类 对象,包括那些由类或接口和那些从超类和超接口继承的声明。 |
int | getModifiers() | 返回此类或接口的Java语言修饰符,以整数编码。 |
String | getName() | 返回由 类 对象表示的实体(类,接口,数组类,原始类型或空白)的名称,作为 String 。 |
Object[] | getSigners() | 获得这个类的签名者。 |
String | getTypeName() | 为此类型的名称返回一个内容丰富的字符串。 |
T | newInstance() | 创建由此 类 对象表示的类的新实例。 |
String | toString() | 将对象转换为字符串。 |
Method类(方法)
Modifier and Type | Method and Description | |
---|---|---|
boolean | equals(Object obj) | 将此 方法 与指定对象进行比较。 |
Annotation[] | getDeclaredAnnotations() | 返回 直接存在于此元素上的注释。 |
int | getModifiers() | 返回由该对象表示的可执行文件的Java语言修饰符,作为整数。(0-default、1-public、2-private、4-protected ) |
String | getName() | 返回由此 方法 对象表示的方法的名称,作为 String 。 |
boolean | isAccessible() | 获取此对象的 accessible 标志的值。 |
Object | invoke(Object obj, Object... args) | 在具有指定参数 方法 对象上调用此 方法 对象的方法。 |
void | setAccessible(boolean flag) | 将此对象的 accessible 标志设置为指示的布尔值。 |
String | toString() | 返回一个描述这个 方法 的字符串。 |
Field类(属性)
Modifier and Type | Method and Description | ||
---|---|---|---|
boolean | equals(Object obj) | 将此 方法 与指定对象进行比较。 | |
Object | get(Object obj) | 返回该所表示的字段的值 Field ,指定的对象上。 | |
Annotation[] | getDeclaredAnnotations() | 返回 直接存在于此元素上的注释。 | |
int | getModifiers() | 返回由该 Field 对象表示的字段的Java语言修饰符,作为整数。(0-default、1-public、2-private、4-protected ) | |
String | getName() | 返回由此 Field 对象表示的字段的名称。 | |
Class<?> | getType() | 返回一个 类 对象标识了此表示的字段的声明类型 Field 对象。 | |
boolean | isAccessible() | 获取此对象的 accessible 标志的值。 | |
void | setAccessible(boolean flag) | 将此对象的 accessible 标志设置为指示的布尔值。 | |
void | set(Object obj, Object value) | 将obj 对象参数上的此 Field 对象表示的字段设置为指定的新值。 | |
String | toString() | 返回一个描述这个 Field 的字符串。 | |
Constructor(构造器)
Modifier and Type | Method and Description | |
---|---|---|
boolean | equals(Object obj) | 将此 Constructor 与指定对象进行比较。 |
int | getModifiers() | 返回由该对象表示的可执行文件的Java语言修饰符,作为整数。(0-default、1-public、2-private、4-protected ) |
String | getName() | 以字符串形式返回此构造函数的名称。 |
int | getParameterCount() | 返回由此对象表示的可执行文件的形式参数(无论是显式声明还是隐式声明)的数量。 |
类<?>[] | getParameterTypes() | 返回一个 类 对象的数组, 类 以声明顺序表示由该对象表示的可执行文件的形式参数 类型。 |
T | newInstance(Object... initargs) | 使用此 Constructor 对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。 |
String | toString() | 返回一个描述这个 Constructor 的字符串。 |
反射相关操作手把手教学
package reflecttest;
public class Person {
public int age;
private String name;
public Person() {
// TODO 自动生成的构造函数存根
}
public Person(String name) {
super();
this.name = name;
}
private Person(String name,int age) {
super();
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(String name,int age) {
System.out.println("迪迦,变身");
}
private void fly() {
System.out.println("迪迦,飞行");
}
private String Work(String name,int age) {
return name;
}
}
获取Class的实例的三种方式
Class的实例就是运行时的类
-
通过类字面常量
Class.class
获取Class clazz = Person.class;
-
通过
Object
类中的getClass()
方法返回一个Class
类型的实例Person person = new Person(); Class clazz = person.getClass();
-
通过静态方法
Class.forName("全类名")
获取类名对应的Class
对象Class clazz = Class.forName("reflecttest.Person");
通过反射创建对象
反射创建类对象主要有两种方式,通过Class
对象的newInstance()
方法、通过Constructor
对象的 newInstance()
方法。
-
第一种:通过
Class
对象的newInstance()
方法。// 获取类的 Class 对象实例 Class clazz = Person.class; //创建Person对象 Person person = (Person)clazz.newInstance();
-
第二种:通过
Constructor
对象的newInstance()
方法// 获取类的 Class 对象实例 Class clazz = Person.class; //创建Person对象 Constructor constructor = clazz.getConstructor(); Person person = (Person)constructor.newInstance();
通过Constructor
对象创建类对象可以选择特定构造方法,而通过 Class
对象则只能使用默认的无参数构造方法。
示例:(调用有参构造方法进行类对象的初始化)
// 获取类的 Class 对象实例
Class clazz = Person.class;
//创建Person对象
Constructor constructor = clazz.getConstructor();
Person person = (Person) constructor.newInstance("迪迦",16);
通过反射调用对象属性
获取属性
获取所有属性的两种方式
-
getFields()
// 通过getFields()获取Person.class及父类中所有 public 修饰的属性 Field[] fields = clazz.getFields();
-
getDeclaredFields()
// 通过getDeclaredFields()获取Person.class中所有的属性 Field[] fields = clazz.getDeclaredFields();
注:
getFields()
可以获取本类及父类中所有 public 修饰的属性
getDeclaredFields()
可以获取本类所有的属性。包括 public、private、protected、default 修饰的属性,不包括父类中的属性
获取指定属性的两种方式
-
getField(String name)
// 通过getField()获取Person.class中的age属性 Field field = clazz.getField("age");
-
getDeclaredField(String name)
// 通过getDeclaredField()获取Person.class中的name属性 Field field = clazz.getDeclaredField("name");
注:
getField(String name)
可以获取本类及父类中的 public 修饰的属性
getDeclaredField(String name)
可以获取本类的属性。包括 public、private、protected、default 修饰的属性,不包括父类中的属性
对属性的操作
设置属性值
// 通过getDeclaredField()获取Person.class中的name属性
Field field = clazz.getDeclaredField("name");
//如果属性是private修饰的,则需要设置访问权限才能赋值
field.setAccessible(true);
//通过set(Object obj, Object value)设置person对象的name属性为"迪迦"
field.set(person, "迪迦");
注:如果属性是private修饰的,则需要设置
setAccessible(true)
才能赋值
获取属性值
//通过get(Object obj)获取person对象的field属性
String name = (String) field.get(person);
获取属性的类型
//通过getType()获取属性的类型
Class type = field.getType();
//获取属性的类型名
String typename = field.getType().getName();
获取属性名
//调用getName()获取属性名
String fieldname = field.getName();
获取修饰类型
//调用getModifiers()获取修饰类型,
int modifier = field.getModifiers();
//Modifier.toString(int mod)转成public、private、protected、default
String modifiername = Modifier.toString(modifier);
注:0-
default
、1-public
、2-private
、4-protected
示例
// 获取类的 Class 对象实例
Class clazz = Person.class;
//创建Person对象
Person person = (Person) clazz.newInstance();
// 通过getDeclaredField()获取Person.class中的name属性
Field field = clazz.getDeclaredField("age");
field.setAccessible(true);
//通过set()设置person对象的age属性为"12"
field.set(person, 12);
//获取修饰符
int modifier = field.getModifiers();
String modifiername = Modifier.toString(modifier);
//获取属性类型名
String typename = field.getType().getName();
//获取属性名
String fieldname = field.getName();
//获取属性值
int fieldvalue = field.getInt(person);
System.out.println(modifiername+" "+typename+" "+fieldname+" = "+fieldvalue+";");
输出:public int age = 12;
通过反射调用对象方法
获取方法
获取所有方法的两种方式
-
getMethods()
//通过getMethods()获取Person类及父类中所有的public修饰的方法 Method[] methods =clazz.getMethods();
-
getDeclaredMethods()
//通过getDeclaredMethods()获取Person类中所有的方法 Method[] methods = clazz.getDeclaredMethods();
注:
getMethods()
可以获取本类及父类中所有 public 修饰的方法
getDeclaredMethods()
可以获取本类所有的方法。包括 public、private、protected、default 修饰的方法,不包括父类中的方法
取指定方法的两种方式
用方法名和形参列表来确定获取的方法
-
getMethod(String name, class<?>... parameterTypes)
//获取Person类中的show方法,参数为方法名,show()的形参列表 Method method =clazz.getMethod("show",String.class,int.class);
-
getDeclaredMethod(String name, 类<?>... parameterTypes)
//获取Person类中的fly方法,参数为方法名,fly()无形参列表 Method method = clazz.getDeclaredMethod("fly");
注:
getMethod()
可以获取本类及父类中的 public 修饰的属性
getDeclaredMethod()
可以获取本类的属性。包括 public、private、protected、default 修饰的属性,不包括父类中的属性
对方法的操作
调用方法
//获取Person类中的fly方法,参数为方法名,fly()无形参列表
Method method = clazz.getDeclaredMethod("fly");
//如果方法是private修饰的,则需要设置访问权限
method.setAccessible(true);
//调用person中的fly方法
method.invoke(person);
//如果方法是静态方法static时,除了上面的方式,也可用下面的方法,当前类调用方法
//method.invoke(Person.class);
注:invoke()方法的返回值和调用的方法的返回值一样
获取方法的参数列表
//获取形参列表
Class[] paramTypes =method.getParameterTypes();
获取方法名
//获取方法名
String methodname = method.getName();
获取方法的修饰类型
//获取方法修饰符
int modifier = method.getModifiers();
String modifiername = Modifier.toString(modifier);
获取方法的返回值类型
//获取返回值类型
Class<?> returntype =method.getReturnType();
//获取返回值类型名
String returntypename = returntype.getName();
示例
public static void main(String[] args) throws Exception, IllegalAccessException {
// 获取类的 Class 对象实例
Class clazz = Person.class;
//创建Person对象
Person person = (Person) clazz.newInstance();
//获取Person类中的方法
Method method = clazz.getDeclaredMethod("Work",String.class,int.class);
//设置权限
method.setAccessible(true);
//获取方法名
String methodname = method.getName();
//获取方法修饰符
int modifier = method.getModifiers();
String modifiername = Modifier.toString(modifier);
//获取返回值类型
Class<?> returntype =method.getReturnType();
//获取返回值类型名
String returntypename = returntype.getName();
//获取形参列表
Class[] paramTypes =method.getParameterTypes();
System.out.print(modifiername+" "+returntypename+" "+methodname+"(");
//打印方法参数
printParamTypes(paramTypes);
}
/**
* 打印方法参数
* @param paramTypes
*/
private static void printParamTypes(Class[] paramTypes) {
for (int j = 0; j < paramTypes.length; ++j) {
if (j > 0) {
System.out.print(",");
}
System.out.print(paramTypes[j].getName());
}
System.out.println(");");
}
输出:private java.lang.String Work(java.lang.String,int);
通过反射调用对象构造方法
获取构造方法
获取所有构造方法的两种方式
-
getConstructors()
//获取所有public修饰的构造方法,不包括父类 Constructor[] constructors = clazz.getConstructors();
-
getDeclaredConstructors()
//获取所有构造方法,包括public、private、protected、default 修饰,不包括父类 Constructor[] constructors = getDeclaredConstructors();
注:
getConstructors()
可以获取本类中所有 public 修饰的构造方法,不包括父类
getgetDeclaredConstructors()
可以获取本类所有的构造方法。包括 public、private、protected、default 修饰的方法,不包括父类
获取指定构造方法的两种方式
对构造器的选择是依赖于形参列表的类型
-
clazz.getConstructor()
//获取无参数的构造方法 Constructor constructor = clazz.getConstructor();
-
getDeclaredConstructor()
//获取形参为(String,int)类型的构造方法 Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);
注:
getConstructor()
只可以获取本类 public 修饰的构造方法,不包括父类
getDeclaredConstructor()
可以获取本类所有的构造方法。包括 public、private、protected、default 修饰的方法,不包括父类
对构造方法的操作
创建对象
对构造器的选择是依赖于形参列表的类型
//获取空参的构造器
//Constructor constructor = clazz.getDeclaredConstructor();
Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);
//如果构造方法是private修饰的,设置权限
constructor.setAccessible(true);
//创建person对象
Person person = (Person)constructor.newInstance("迪迦",20);
获取构造方法的参数列表
//获取构造方法形参列表
Class[] paramTypes = constructor.getParameterTypes();
获取构造方法名
//获取构造方法名
String constructorname = constructor.getName();
获取构造方法的修饰类型
//获取构造方法的修饰符
int modifier = constructor.getModifiers();
String modifiername = Modifier.toString(modifier);
示例
public static void main(String[] args) throws Exception, IllegalAccessException {
// 获取类的 Class 对象实例
Class clazz = Person.class;
//获取带参的构造器
Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class);
//如果构造方法是private修饰的,设置权限
constructor.setAccessible(true);
//创建person对象
Person person = (Person)constructor.newInstance("迪迦",20);
//获取构造方法名
String constructorname = constructor.getName();
//获取构造方法的修饰符
int modifier = constructor.getModifiers();
String modifiername = Modifier.toString(modifier);
//获取构造方法形参列表
Class[] paramTypes = constructor.getParameterTypes();
System.out.print(modifiername+" "+constructorname+"(");
//打印方法参数
printParamTypes(paramTypes);
}
/**
* 打印方法参数
* @param paramTypes
*/
private static void printParamTypes(Class[] paramTypes) {
for (int j = 0; j < paramTypes.length; ++j) {
if (j > 0) {
System.out.print(",");
}
System.out.print(paramTypes[j].getName());
}
System.out.println(");");
}
输出:private test1.Person(java.lang.String,int);