反射的通俗理解
反射对初学者来说是一个比较难以理解的概念,其深入的理解涉及到了java虚拟机的知识,但是我们可以简单理解并加以应用。我们知道java对象都是通过类创造的,对此我们可以理解反射是通过拿到类对象并通过操作类对象成员生成一个实例对象,并进行方法的调用。
类对象的成员包括:构造方法,属性,方法
反射的简单应用
1:首先得到类对象(三种方法)
// 类对象
Class<?> exampleClass = null;
// 通过类名获取
exampleClass = Class.forName("com.liu.example"); // 包名.类名
// 方式二:每个类下的静态属性 class
exampleClass = ExampleClass.class;
// 方式三:Object类下的getClass(),通过实例对象获取
Example example = new Example();
exampleClass = example.getClass();
三种方式简单对比:
- 方式一通过全限定类名字符串既可以获取,其他两种方式都要导入类Example才可以;
- 方式二获取的Class不需要强转即可获得指定类型Class,其他两种方式获得的都是未知类型Class<?>;
- 方式三通过实例化对象的Object中的方法获取,其他两种都不需要实例化对象。
怎么选:
- 只有全限定类名字符串,没有具体的类可以导入的只能选方式一;
- 有具体类导入没有实例化对象的使用方式二;
- 作为形参使用的使用方式三,通过形参引用来获取Class。
2:反射常用API
java.lang.Class:代表一个类
方法名 | 功能说明 |
---|---|
static Class forName(String name) | 返回指定类名 name 的 Class 对象 |
Object newInstance() | 调用缺省构造函数,返回该Class对象的一个实例 |
getName() | 返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称 |
Class getSuperClass() | 返回当前Class对象的父类的Class对象 |
Class [] getInterfaces() | 获取当前Class对象的接口 |
ClassLoader getClassLoader() | 返回该类的类加载器 |
Class getSuperclass() | 返回表示此Class所表示的实体的超类的Class |
2.1 java.lang.reflect.Constructor:代表类的构造器
通过类对象获取构造器的方法
方法名 | 功能说明 |
---|---|
Constructor<?>[] getDeclaredConstructors() | 所有构造方法 |
Constructor<?>[] getConstructors() | 所有public构造方法 |
Constructor<?> getConstructor();//参数类型为null,表示无参 | 无参构造方法 |
Constructor<?> getDeclaredConstructor(String.class) | 单个私有构造方法 参数类型根据自己定义的来 |
2.2 java.lang.reflect.Field:代表类的成员变量
通过类对象获取成员变量的方法
方法名 | 功能说明 |
---|---|
Field[] getDeclaredFields(); | 获取所有成员变量 |
Field[] getFields() | 获取所有公共成员变量 |
Field getField(“name”) | 获取单个公共成员变量 |
Field getDeclaredField(“name”) | 获取单个私有成员变量 |
2.3 java.lang.reflect.Method:代表类的方法
通过类对象获取方法成员的方法
方法名 | 功能说明 |
---|---|
Method[] getDeclaredMethods() | .获取所有方法–不会获取父类的方法 |
Method[] getMethods() | 获取所有公共方法–会获取父类的方法 |
Method getMethod(“printName”); //方法名称 | 获取单个公共方法,无参方法 |
Method getMethod(“printName”,String.class); //方法名称,参数类型 | 获取单个公共方法–有参方法 |
Method getDeclaredMethod(“printName”) | 获取单个私有方法 |
获取的方法虽然多但是挺好记的,首先类的成员有Constructor、Method、Field
获取所有的: get+Declared+成员名+s
获取所有公共的: get+成员名+s
获取单个的:get+成员名
获取私有单个的:get+Declared+成员名
案例:
一个要被反射获取的类
package array;
/**
*
* @author Administrator
*/
public class Example {
public String testString;
//测试用
private int id;
private String name;
// 无参构造方法
public Example() {
System.out.println("====无参构成方法被调用");
}
// 多个参数构造方法
public Example(int id, String name) {
this.id = id;
this.name = name; }
// default构造方法--测试
Example(String name, int id){
this.id = id;
this.name = name; }
// 受保护构造方法--测试
protected Example(int id) {
this.id = id; }
// 私有构造方法--测试
private Example(String name) {
this.name = name; }
public int getId() {
return id; }
public void setId(int id) {
this.id = id; }
public String getName() {
return name; }
public void setName(String name) {
this.name = name; }
@Override public String toString() {
return "Example{ id=" + id + ", name=" + name + "}";
}
public void printName(){
System.out.println("====printName--"+this.name); }
public void printName(String name){
this.name = name;
System.out.println("====printName--"+this.name); }
private void demoTest(){
System.out.println("====demoTest--执行了");
}
}
测试
/**
* @Author LMY
* @Date2022/7/4 15:56
* @PackageName: ${PACKAGE.NAME}
* @Description:
* @Version 1.0
*/
public class RefTest2 {
/**
* 案例一:构造方法、成员变量和成员方法的获取和使用
*/
public static void main(String[] args) throws Exception {
Class<?> exampleClass = Class.forName("array.Example");
// 1.构造方法操作
// 1.1.获取所有构造方法
System.out.println("1.构造方法操作\n1.1.所有构造方法");
Constructor<?>[] declaredConstructors = exampleClass.getDeclaredConstructors();
for (Constructor constructor : declaredConstructors) {
System.out.println(constructor.toString()); // Constructor类的toString已重写
}
// 1.2.获取所有public构造方法
System.out.println("1.2.所有public构造方法");
Constructor<?>[] constructors = exampleClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor.toString());
}
// 1.3.获取无参构造方法
Constructor<?> onParamConstructor = exampleClass.getConstructor();//参数类型为null,表示无参
System.out.println("1.3.无参构造方法:\n" + onParamConstructor.toString());
// 实例化对象
Object o = onParamConstructor.newInstance();
if (o instanceof Example) {
Example example = (Example) o;
example.setId(111);
example.setName("myName");
System.out.println(o.toString());// Children类重写了toString
}
// 1.4.获取单个私有构造方法
// 指定了私有构造方法的参数类型,所以只会获取到一个构造方法
Constructor<?> privateConstructor = exampleClass.getDeclaredConstructor(String.class);
System.out.println("1.4.单个私有构造方法:\n" + privateConstructor.toString());
//私有构造方法需要取消访问权限检查,否则报异常:IllegalAccessExceptionw
privateConstructor.setAccessible(true);
Object obj = privateConstructor.newInstance("myName");
System.out.println(o.toString());
// 2.字段操作(成员变量)
// 2.1.获取所有成员变量
System.out.println("2.字段操作(成员变量)\n2.1.获取所有成员变量");
Field[] declaredFields = exampleClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
// 获取fieldName
System.out.println(declaredField.getName());
}
// 2.2.获取所有公共成员变量
System.out.println("2.2.获取所有公共成员变量");
Field[] fields = exampleClass.getFields();
for (Field field : fields) {
// 获取fieldName
System.out.println(field.getName());
}
// 2.3.获取单个公共成员变量
System.out.println("2.3.获取单个公共成员变量");
Field field = exampleClass.getField("testString");
Object o1 = exampleClass.getConstructor().newInstance();
field.set(o1, "yty");
Object o1_1 = field.get(o1);
// 获取fieldName
System.out.println("成员变量名-值:" + field.getName() + "=" + o1_1.toString());
// 2.4.获取单个私有成员变量
System.out.println("2.4.获取单个私有成员变量");
Field field2 = exampleClass.getDeclaredField("name");
//私有成员变量需要取消访问权限检查,否则报异常:IllegalAccessExceptionw
field2.setAccessible(true);
Object o2 = exampleClass.getConstructor().newInstance();
field2.set(o2, "myName");
Object o2_2 = field2.get(o2);
// 获取fieldName
System.out.println("成员变量名-值:" + field2.getName() + "=" + o2_2.toString());
// 3.方法操作(成员方法)
// 3.1.获取所有方法(成员方法)
System.out.println("3.方法操作(成员方法)\n3.1.获取所有方法--不会获取父类的方法");
Method[] declaredMethods = exampleClass.getDeclaredMethods();
for (Method method : declaredMethods) {
// 获取方法名
System.out.println(method.getName());
}
// 3.2.获取所有公共方法
System.out.println("3.2.获取所有公共方法--会获取父类的方法");
Method[] methods = exampleClass.getMethods();
for (Method method : methods) {
// 获取方法名
System.out.println(method.getName());
}
// 3.3.获取单个公共方法
System.out.println("3.3.获取单个公共方法\n3.3.1.获取单个公共方法--无参方法");
Method printName = exampleClass.getMethod("printName"); //方法名称
System.out.println(printName);
System.out.println("3.3.2.获取单个公共方法--有参方法");
Method printName2 = exampleClass.getMethod("printName", String.class); //方法名称,参数类型
System.out.println("参数个数:" + printName2.getParameterCount());
// 遍历所有参数信息
Parameter[] parameters = printName2.getParameters();
for (int i = 0; i < printName2.getParameterCount(); i++) {
Parameter param = parameters[i];
if (param.isNamePresent()) {
System.out.println("第" + (i + 1) + "个参数信息");
System.out.println("参数类型=" + param.getType());
System.out.println("参数名称=" + param.getName());
}
}
// 使用有参方法
Object o3 = exampleClass.getConstructor().newInstance();
printName2.invoke(o3, "myName");//传入参数值、执行方法
// 3.4.获取单个私有方法
System.out.println("3.4.获取单个私有方法");
Method demoTest = exampleClass.getDeclaredMethod("demoTest");
// 使用私有无参方法
Object o4 = exampleClass.getConstructor().newInstance();
demoTest.setAccessible(true);
demoTest.invoke(o4);
}
}