一、前置知识点
1、运行java程序需要java虚拟机(JVM)
2、我们编写的java代码需要被编译成.class文件
3、.class文件会被类加载器加载到java虚拟机当中
4、.class文件记录着类的所有的信息
个人理解:
计算机通过加载到的.class文件已经知道类的所有信息了,但是为了让人也能知道这个类中描述的所有信息,所以才有了反射,就是将类的详细信息以对象的形式表达出来,方便人去进行手动管理。
就像汽车一样,原本我们使用汽车能开就可以了,但是难免有人想改装它,这时候就需要提供这个车子的架构图了。个人觉得之所以有反射,就是这个道理。
二、测试实例
(1)基础类
测试注解
package com.suncy.article.article10;
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRefAnnotation {
}
测试基础类
两个构造方法,两个成员变量,两个成员方法
package com.suncy.article.article10;
import org.springframework.beans.factory.annotation.Value;
//添加测试注解
@MyRefAnnotation
public class MyRefTest {
public int a;
private String b;
public MyRefTest() {
}
private MyRefTest(String b) {
this.b = b;
}
public MyRefTest(int a) {
this.a = a;
}
@Value("444")
public void testA(String a) throws Exception{
System.out.println("ttttt" + a);
}
private void testB() {
}
}
(2) Class<?> 对象提供的一些方法
package com.suncy.article.article10;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
public class ReflexTestMain {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException,
IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
//基本获取方法
System.out.println("=====================获取Class<?>的三种方式=====================");
MyRefTest myRefTest = new MyRefTest();
Class<?> cls = myRefTest.getClass();
System.out.println("myRefTest.getClass() : " + cls);
Class<?> cls1 = MyRefTest.class;
System.out.println("MyRefTest.class : " + cls1);
Class<?> cls2 = Class.forName("com.suncy.article.article10.MyRefTest");
System.out.println("Class.forName(xxx) : " + cls2);
System.out.println();
//基本使用方法
//一、获取构造方法
//1、获取所有的公有构造方法
System.out.println("=======================获取Constructor<?>=========================");
Constructor<?>[] constructors = cls.getConstructors();
System.out.println("cls.getConstructors() : " + Arrays.toString(constructors));
//2、获取所有构造方法 包括私有的 受保护的
Constructor<?>[] constructors1 = cls.getDeclaredConstructors();
System.out.println("cls.getDeclaredConstructors() : " + Arrays.toString(constructors1));
//3、获取公有的无参构造方法
Constructor<?> constructor = cls.getConstructor();
System.out.println("cls.getConstructor() : " + constructor);
//4、调用构造方法 生成对象
System.out.println("通过constructor实例化对象");
MyRefTest myRefTest1 = (MyRefTest) constructor.newInstance();
System.out.println("myRefTest : " + myRefTest);
System.out.println("myRefTest1 : " + myRefTest1);
System.out.println();
System.out.println("=======================获取Field=========================");
//二、获取成员变量
//1、获取所有的公有字段
Field[] fields = cls.getFields();
System.out.println("cls.getFields() : " + Arrays.toString(fields));
//2、获取所有的字段
Field[] fields1 = cls.getDeclaredFields();
System.out.println("cls.getDeclaredFields() : " + Arrays.toString(fields1));
//3、获取某个公有字段
Field fieldA = cls.getField("a");
System.out.println("cls.getField(xx) : " + fieldA);
//4、获取某个字段,包含私有的
Field fieldB = cls.getDeclaredField("b");
System.out.println("cls.getDeclaredField(xx) : " + fieldB);
System.out.println();
System.out.println("======================获取Method=========================");
//三、获取成员方法
//1、获取所有公有的成员方法
Method[] methods = cls.getMethods();
System.out.println("cls.getMethods() : " + Arrays.toString(methods));
//2、获取所有的成员方法 包含私有
Method[] methods1 = cls.getDeclaredMethods();
System.out.println("cls.getDeclaredMethods() : " + Arrays.toString(methods1));
//3、获取某个公有字段
Method methodA = cls.getMethod("testA", String.class);
System.out.println("cls.getMethod(xx, String.class) : " + methodA);
//4、获取某个字段,包含私有的
Method methodB = cls.getDeclaredMethod("testB");
System.out.println("cls.getDeclaredMethod(xx) : " + methodB);
System.out.println();
System.out.println("======================获取类上的Annotation==========================");
//四、获取类注解
//1、获取类上所有的注解
Annotation[] annotations = cls.getAnnotations();
System.out.println("cls.getAnnotations() : " + Arrays.toString(annotations));
//2、获取类上特定的注解
MyRefAnnotation annotation = cls.getAnnotation(MyRefAnnotation.class);
System.out.println("cls.getAnnotation(xx) : " + annotation);
//3、获取不存在的注解 会返回null
Override annotation1 = cls.getAnnotation(Override.class);
System.out.println("cls.getAnnotation(xx) : " + annotation1);
System.out.println();
//五、判断类的类型
System.out.println("======================判断类的类型==========================");
System.out.println("cls.isArray() : " + cls.isArray()); //数组类
System.out.println("cls.isAnnotation() : " + cls.isAnnotation()); //注解类
System.out.println("cls.isAnnotationPresent(xx) : " + cls.isAnnotationPresent(MyRefAnnotation.class)); //特定注解类
System.out.println("cls.isInterface() : " + cls.isInterface()); //接口类
System.out.println("cls.isLocalClass() : " + cls.isLocalClass()); //局部类
System.out.println("cls.isEnum() : " + cls.isEnum()); //枚举类
System.out.println("cls.isAnonymousClass() : " + cls.isAnonymousClass()); //匿名类
System.out.println("cls.isMemberClass() : " + cls.isMemberClass()); //内部类
System.out.println("cls.isInstance(xx) : " + cls.isInstance(myRefTest)); //判断对象是否是该类实例
System.out.println();
System.out.println("=======================Class<?>中的其他方法=========================");
//六、其他方法
//获取类加载器
ClassLoader classLoader = cls.getClassLoader();
System.out.println("cls.getClassLoader() : " + classLoader);
Class<?>[] classes = cls.getClasses();
System.out.println("cls.getClasses() : " + Arrays.toString(classes));
Class<?>[] classes1 = cls.getDeclaredClasses();
System.out.println("cls.getDeclaredClasses() : " + Arrays.toString(classes1));
//获取类的名称(完整路径)
String name = cls.getName();
System.out.println("cls.getName() : " + name);
//获取类的名称(类名称)
String name1 = cls.getSimpleName();
System.out.println("cls.getSimpleName() : " + name1);
//获取类的名称(获取所传类从java语言规范定义的格式输出)
String name2 = cls.getCanonicalName();
System.out.println("cls.getCanonicalName() : " + name2);
//获取父类类型
Class<?> clsSuperclass = cls.getSuperclass();
System.out.println("cls.getSuperclass() : " + clsSuperclass);
//获取接口类型
Class<?>[] clsSuperclass1 = cls.getInterfaces();
System.out.println("cls.getInterfaces() : " + Arrays.toString(clsSuperclass1));
//获取包名
Package clsPackage = cls.getPackage();
System.out.println("cls.getPackage() : " + clsPackage);
}
}
响应结果
(3) Method、Field、Annotation提供的一些方法
package com.suncy.article.article10;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
public class ReflexTestMain1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException,
IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
Class<?> cls = Class.forName("com.suncy.article.article10.MyRefTest");
//拿到Constructor对象
Constructor<MyRefTest> constructor = (Constructor<MyRefTest>) cls.getConstructor();
System.out.println("拿到MyRefTest类的Constructor对象 : " + constructor);
//根据constructor实例化对象
MyRefTest myRefTest = constructor.newInstance();
System.out.println("根据这个myRefTest的constructor构造对象(constructor.newInstance()) : " + myRefTest);
//拿到cls所有方法
Method[] methods = cls.getMethods();
System.out.println("拿到这个类所有公有成员方法(cls.getMethods()) : " + Arrays.toString(methods));
System.out.println();
//拿到cls特定的某个方法 执行myRefTest对象的这个特定的方法
System.out.println("=============testA方法对应的Method对象================");
Method methodTestA = cls.getMethod("testA", String.class);
System.out.println("拿到testA方法的Method : " + methodTestA);
// 调用对象方法
System.out.println("调用testA方法 : ");
methodTestA.invoke(myRefTest, "22312312");
//拿到这个特定Method方法上的注解
System.out.println("拿到methodA方法上的注解 : " + Arrays.toString(methodTestA.getDeclaredAnnotations()));
//拿到这个特定Method方法上的异常
System.out.println("拿到methodA方法上的异常 : " + Arrays.toString(methodTestA.getExceptionTypes()));
System.out.println();
//给myRefTest对象的a字段设置值 通过Field对象拿到这个a字段的值
System.out.println("=============a字段对应的Field对象================");
myRefTest.a = 34;
Field fieldA = cls.getField("a");
System.out.println("拿到a字段Field : " + fieldA);
System.out.println("拿到字段a的值 : " + fieldA.getInt(myRefTest));
System.out.println("是否能反射出a字段属性值 : " + fieldA.isAccessible());
//设置是否能反射该属性数
System.out.println("修改是否能反射a字段属性值 : fieldA.setAccessible(true)");
fieldA.setAccessible(true);
System.out.println("是否能反射出a字段属性值 : " + fieldA.isAccessible());
System.out.println("是否是枚举类型的元素 : " + fieldA.isEnumConstant());
System.out.println();
//拿到cls类上持有的注解
System.out.println("==========MyRefAnnotation注解对应的Annotation对象================");
Annotation annotation = cls.getAnnotation(MyRefAnnotation.class);
System.out.println("获取MyRefAnnotation注解的Annotation : " + annotation);
//返回cls类的规范名称(获取所传类从java语言规范定义的格式输出)
System.out.println("拿到类的规范名称 : " + cls.getCanonicalName());
//返回注解的注解类型
System.out.println("拿到注解的annotationType : " + annotation.annotationType());
//返回注解的规范名称(获取所传类从java语言规范定义的格式输出)
System.out.println("拿到注解的规范名称 : " + annotation.annotationType().getCanonicalName());
}
}
响应结果
三、总结
1、反射相关类:Class、Constructor、Method、Field、Annotation。
2、代理常用的一种方式是: methodTestA.invoke(myRefTest, "22312312");
methodTestA表示一个特定的Method对象。myRefTest表示对象。22312312表示参数、参数数量需要去看Method指定方法的参数是多少。
3、多写demo测试一下,更为直观,印象更深。