目录
Java中的许多对象在运行时都有两种类型:
- 编译时类型
- 运行时类型
在程序运行时获取对象的真实信息有以下两种做法:
- 在知道对象的具体类型的情况下,可以先使用instanceof运算符进行判断,再使用强制类型转换将其转化成运行时的类型变量即可
- 在无法预知该对象是属于哪些类的情况下,必须通过反射来发现该对象和类的真实信息
反射机制允许程序运行时借助Reflection API取得任何类的内部信息,并能直接操作对象的内部属性和方法
Reflection API提供了Constructor、Field和Method类,分别用于描述类的构造方法、属性和方法
Java反射机制的功能:
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时获取任意一个类的成员变量和方法
- 在运行时调用任意一个对象的方法
- 生成动态代理
如:获取类对象的所有方法
import java.lang.reflect.Method;
public class Demo {
public static void main(String[] args) throws ClassNotFoundException {
Class cs = Class.forName("java.lang.String"); // 获取String类的Class对象
Method[] methods = cs.getDeclaredMethods(); // 获取当前类对象的所有方法
for (Method method: methods
) {
System.out.println(method);
}
}
}
1.Executable抽象类
Executable抽象类派生出了Constructor和Method两个子类,其提供了大量方法来获取参数、修饰符或注解等信息
方法 | 功能 |
Parameter[ ] getParameters() | 获取所有形参,返回一个数组 |
int getParameterCount() | 获取形参个数 |
abstract int getModifiers() | 获取修饰符,返回的整数是修饰符public、protected、private、final、static、abstract等关键字所对应的常量 |
boolean isVarArgs() | 判断是否包含数量可变的形参 |
2.Constructor类
Constructor类用于表示类的构造方法,通过调用Class对象的getConstructors()方法可以获取当前类的构造方法的集合
方法 | 功能 |
String getName() | 返回构造方法的名称 |
Class[ ] getParameterTypes() | 返回当前构造方法的参数类型 |
int getModifiers() | 获取修饰符的整形标识,返回的整数是修饰符public、protected、private、final、static、abstract等关键字所对应的常量,需要使用Modifier工具类的方法解码后才能获得真实的修饰符 |
package reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
public class ConstructorDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 1.获取String类的对象
Class cs = Class.forName("java.lang.String");
// 2.返回所有构造方法
Constructor[] constructors = cs.getConstructors();
// 3.遍历所有构造方法
for (Constructor constructor : constructors) {
// 4.输出构造方法的名称
String constructorName = constructor.getName();
System.out.println(constructorName+"()");
// 5.获取构造方法修饰符的整型标识
int mod = constructor.getModifiers();
// 6.使用Modifier工具类的方法输出真实的修饰符
String modifier = Modifier.toString(mod);
System.out.println(modifier);
// 7.获取构造方法的参数类型
Class[] paraTypes = constructor.getParameterTypes();
// 8.输出构造方法的参数类型名称
for (Class cas : paraTypes) {
System.out.print(cas.getName() + " ");
}
System.out.println("\n------------------------");
}
}
}
3.Method类
Method类用于封装方法的信息,调用Class对象的getMethods()方法或getMethod()可以获取当前类的所有方法或指定方法
方法 | 功能 |
String getName() | 返回方法的名称 |
Class[ ] getParameterTypes() | 返回当前方法的参数类型 |
int getModifiers() | 返回修饰符的整形标识 |
Class getReturnType() | 返回当前方法的返回类型 |
package reflect;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class MethodDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 1.获取String类的对象
Class cs = Class.forName("java.lang.String");
// 2.返回所有方法
Method[] methods = cs.getMethods();
// 3.遍历所有方法
for (Method method : methods) {
// 4.输出方法的名称
String methodName = method.getName();
System.out.println(methodName+"()");
// 5.获取方法修饰符的整型标识
int mod = method.getModifiers();
// 6.使用Modifier工具类的方法输出真实的修饰符
String modifier = Modifier.toString(mod);
System.out.println(modifier);
// 7.获取方法的参数类型
Class[] paraTypes = method.getParameterTypes();
// 8.输出方法的参数类型名称
for (Class cas : paraTypes) {
System.out.print(cas.getName() + " ");
}
System.out.println("\n------------------------");
}
}
}
4.Field类
Field类用于封装属性的信息,调用Class对象的getFields()或getField()方法可以获取当前类的所有属性或指定属性
方法 | 功能 |
String getName() | 返回属性的名称 |
int getModifiers() | 返回修饰符的整型标识 |
getXxx(Object obj) | 获取属性的值,此处Xxx对应Java8中的基本类型,如果属性是引用类型,直接使用get(Object obj)方法 |
setXxx(Object obj,Xxx val) | 设置属性的值,此处Xxx对应Java8中的基本类型,如果属性是引用类型,直接使用set(Object obj,Object val)方法 |
Class[ ] getType() | 返回当前属性的类型 |
package reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
class Student{
private String name;
protected int age;
public String toString(){
return ("姓名:" + name + "---" + "年龄:" + age);
}
}
public class FieldDemo {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
// 1.获取Student类对应的Class对象
Class studentClass = Student.class;
// 2.返回所有属性(不包括超类属性)
Field[] fields = studentClass.getDeclaredFields();
// 3.遍历所有属性
for (Field field : fields) {
// 4.输出属性的类型
Class fieldType = field.getType();
System.out.println(fieldType);
// 5.获取属性的修饰符
int mod = field.getModifiers();
// 6.使用Modifier工具类输出修饰符对应的常量
String val = Modifier.toString(mod);
System.out.println(val);
// 7.输出属性的名称
String fieldName = field.getName();
System.out.println(fieldName);
System.out.println("----------------");
}
// 1.创建一个Student对象
Student student = new Student();
// 2.获取Student类的属性对象
// getDeclaredField:获取各种访问控制符的成员变量
Field nameField = studentClass.getDeclaredField("name");
Field ageField = studentClass.getDeclaredField("age");
// 3.设置通过 反射 访问该类成员变量时取消访问权限检查
nameField.setAccessible(true);
ageField.setAccessible(true);
// 4.获取Student类Class对象对应的实例
Object obj = studentClass.newInstance();
// 5.获取Student类的属性对象的值
String name = (String) nameField.get(obj);
int age = ageField.getInt(obj);
System.out.println("Student类属性对象的值:" + name + ":" + age);
// 6.设置Student类的属性对象的值
nameField.set(student,"lisi");
ageField.setInt(student,18);
// 7.输出对象student的信息(默认调用toString()方法)
System.out.println(student);
}
}
5.Parameter类
每个Parameter对象代表方法的一个参数,调用Class对象getParameters()可以获取当前方法的所有参数,Parameter类中提供许多方法获取参数信息
方法 | 功能 |
int getModifiers() | 返回参数的修饰符的整型标识 |
String getNmae() | 返回参数的形参名 |
Type getParameterizedType() | 获取带泛型的形参类型 |
Class<?> getType() | 获取形参类型 |
boolean isVarArgs() | 判断该参数是否是可变参数 |
boolean isNamePresent() | 判断.class文件中是否包含方法的形参名信息 |
package reflect;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
class MethodParameter{
public void test1(String str){
}
public void test2(int val, boolean bool){
}
}
public class ParameterDemo {
public static void main(String[] args) {
// 1.获取MethodParameter类的Class对象
Class cls = MethodParameter.class;
// 2.获取MethodParameter类的所有方法
Method[] methods = cls.getMethods();
// 3.遍历MethodParameter类的所有方法
for (Method method : methods) {
// 4.输出该方法名
String methodName = method.getName();
System.out.println("方法名:" + methodName);
// 5.输出该方法的形参个数
int count = method.getParameterCount();
System.out.println("形参个数:" + count);
// 6.获取该方法的所有参数
Parameter[] parameters = method.getParameters();
// 7.遍历该方法的所有参数
for (Parameter parameter : parameters) {
// 8.输出参数名
System.out.println("参数名:" + parameter.getName());
// 9.输出形参类型
System.out.println("形参类型:" + parameter.getType());
// 10.输出泛型类型
System.out.println("泛型类型:" + parameter.getParameterizedType());
System.out.println("——————————————————————————————");
}
}
}
}
使用javac命令编译java源文件时,默认生成的.class文件不包含方法形参名信息,所以调用getName()不能得到正确的形参名
如果希望javac命令编译java源文件时保留形参信息,则需要为编译命令指定-parameters选项