反射
反射库提供了的工具集可以用来编写能够动态操作Java代码的程序,使用反射,Java可以支持用户界面生成器、对象关系映射器以及很多其他需要动态查询能力的开发工具。
能够分析类能力的程序称为反射。
反射机制可以用来:
- 在运行时分析类的能力。
- 在运行时检查对象,例如,编写一个适用于所有类的toString方法。
- 实现泛型数组操作代码。
- 利用Method对象,这个对象很像C++中的指针。
Class类
在程序运行期间,Java运行时系统始终为所有对象维护一个运行时类型标识。这个信息会跟踪每个对象所属的类。虚拟机利用运行时类型信息选择要执行的正确方法。
可以使用一个特殊的Java类访问这些信息,保存这些信息的类名为Class。Class对象会描述一个特定类的属性。
获取Class对象的方式
-
静态方法Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象。
多用于配置文件,将类名定义在配置文件中。读取文件,加载类。
可通过调用Class.forName手工强制加载类。
String className = "java.util.Random"; Class cl = Class.forName(className);
如果类名保存在一个字符串中,这个字符串会在运行时变化,就可以使用这个方法。如果className是一个类名或接口名,这个方法可以正常运行,否则forName方法将抛出一个检查型异常。使用这个方法应该提供一个异常处理器。
-
类名.Class:通过类名的属性class获取。
多用于参数传递。
如果T是任意Java类型(或void关键字),T.class将代表匹配的类对象。
Class cl1 = Random.class; Class cl2 = int.class; Class cl3 = Double[].class;
一个Class对象实际上表示的是一个类型,这可能是类,也可能不是类。例如int不是类,但int.class是一个Class类型的对象。
-
对象.getClass():返回一个Class类型的实例。此方法在Object类中。
多用于对象的获取字节码的方式。
Employee e; Class cl = e.getClass();
Class对象功能
获取功能
1. 获取成员变量
-
Field[] getFields()
获取public修饰的成员变量并返回包含这些Field对象的数组,这些对象对应这个类或其超类的公共字段。
-
Field getField(String name)
获取指定名称的public修饰成员变量返回Field对象
-
Field[] getDeclaredFields()
获取本类所有成员变量并返回包含这些Field对象的数组,这些对象对应这个类的全部字段。如果类中没有字段,或者Class对象描述的是基本类型或数组类型,这些方法将返回一个长度为0的数组。
-
Field getDeclaredField(String name)
获取指定名称的成员变量并返回Field对象
操作操作成员变量
-
获取值:get(Object obj)
-
设置值:void set(object obj,Object value)
-
忽略访问权限修饰符的安全检查:setAccessible(true) 暴力反射
public class Person {
private String name;
protected int age;
int id;
public int score;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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;
}
public void eat(){
System.out.println("吃饭");
}
public void eat(String name){
System.out.println(name+"吃饭");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", id=" + id +
", score=" + score +
'}';
}
}
import java.lang.reflect.Field;
public class ReflectDamo01 {
public static void main(String[] args) throws Exception {
Class pc = Person.class;
//获取成员变量
Field[] fields = pc.getFields();
for (Field f : fields) {
System.out.println(f);
}//这个方法只能获取到公共变量score
Field[] declearedFields = pc.getDeclaredFields();
for (Field e : declearedFields) {
System.out.println(e);
}//获取本类所有成员变量
Field field = pc.getField("score");
//获取成员变量score的值
Person p = new Person();
Object value = field.get(p);
System.out.println(value);
//设置成员变量score的值
field.set(p,100);
System.out.println(p);
Field name = pc.getDeclaredField("name");
//忽略访问权限修饰符的安全检查
name.setAccessible(true);//暴力反射
Object v2 = name.get(p);
System.out.println(v2);
}
}
2. 获取构造方法
-
Constructor[] getConstructors()
返回包含一个数组
Constructor
对象反射由此表示的类的所有public公共构造类
对象。 -
Constructor getConstructor(类… parameterTypes)
返回一个
Constructor
对象,该对象反映Constructor
对象表示的类的指定的public公共类
函数。 -
Constructor[] getDeclaredConstructors()
返回一个反映
Constructor
对象表示的类声明的所有Constructor
对象的数组类
。 -
Constructor getDeclaredConstructor(类… parameterTypes)
返回一个
Constructor
对象,该对象反映Constructor
对象表示的类或接口的指定类
函数。
创建对象
-
T newInstance(Object… initargs)
使用此
Constructor
对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例 -
T newInstance()
创建由此
类
对象表示的类的新实例。
import java.lang.reflect.Constructor;
public class ReflectDamo02 {
public static void main(String[] args) throws Exception {
Class pc = Person.class;
//获取有参构造器class对象
Constructor constructor = pc.getConstructor(String.class, int.class);
System.out.println(constructor);
//创建对象
Object obj = constructor.newInstance("小明",15);
System.out.println(obj);
//使用空参构造器创建对象可以使用class对象的newInstance方法
Object o = pc.newInstance();
System.out.println(o);
//constructor.setAccessible(true); 暴力反射
}
}
3. 获取成员方法
-
Method[] getMethods()
返回包含一个数组
方法
对象反射由此表示的类或接口的所有public公共方法类
对象,包括那些由类或接口和那些从超类和超接口继承的声明。 -
Method getMethod(String name, 类… parameterTypes)
返回一个
方法
对象,它反映此表示的类或接口的指定public公共成员方法类
对象。 -
Method[] getDeclaredMethods()
返回包含一个数组
方法
对象反射的类或接口的所有声明的方法,通过此表示类
对象,包括公共,保护,默认(包)访问和私有方法,但不包括由超类继承的方法。 -
Method getDeclaredMethod(String name, 类… parameterTypes)
返回一个
方法
对象,它反映此表示的类或接口的指定声明的方法类
对象。
执行方法
-
Object invoke(Object obj, Object… args)
在具有指定参数的方法对象上调用此方法对象表示的底层方法。
-
获取方法名:String getName()
import java.lang.reflect.Method;
public class ReflectDamo03 {
public static void main(String[] args) throws Exception {
Class pc = Person.class;
//获取指定名称的方法对象
Method eatMethod = pc.getMethod("eat");
//执行空参方法
Person p = new Person();
eatMethod.invoke(p);
//执行有参方法
Method method = pc.getMethod("eat", String.class);
method.invoke(p,"小明");
//获取方法名
String name = method.getName();
System.out.println(name);
//获取所有超类(Object类)和子类的public方法
Method[] methods = pc.getMethods();
for (Method m : methods) {
System.out.println(m);
}
//method.setAccessible(true);暴力反射
}
}
4. 获取类名
-
String getName()
返回由
类
对象表示的实体(类,接口,数组类,原始类型或空白)的名称,作为String
。
String classname = pc.getName();
System.out.println(classname);