反射

实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @NoArgsConstructor public class Student { private String name; private int age;
public Student(String name, int age) { this.name = name; this.age = age; }
public void hello () { System.out.println("Hello, I'm " + name + ", " + age + " years old."); }
public String study () { return "I'm studying."; }
public void eat(String EatName) { System.out.println(this.name + " is eating " + EatName); } }
|
Class对象
1 2 3 4 5 6 7 8 9
| @Test public void test() throws ClassNotFoundException { Class<Student> studentClass01 = Student.class; Class<?> studentClass02 = Class.forName("com.example.Student"); Student student = new Student(); Class<? extends Student> studentClass03 = student.getClass(); System.out.println(studentClass01 == studentClass02); System.out.println(studentClass02 == studentClass03); }
|
运行结果发现输出为真说明类的class对象在内存中是唯一的
类的构造器
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Test public void constructorStudy() throws Exception { Class<Student> studentClass = Student.class; Constructor<?>[] constructors = studentClass.getDeclaredConstructors(); Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor(String.class, int.class);
System.out.println(Arrays.toString(constructors)); System.out.println(declaredConstructor); System.out.println(declaredConstructor.getParameterCount());
Student student = declaredConstructor.newInstance("Tom", 18); System.out.println(student); }
|
可以通过反射获取构造器来构造对象
类的方法
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Test public void methodStudy() throws Exception { Class<Student> studentClass = Student.class; Method[] declaredMethods = studentClass.getDeclaredMethods(); Method hello = studentClass.getDeclaredMethod("hello"); Method study = studentClass.getDeclaredMethod("study"); Method eat = studentClass.getDeclaredMethod("eat", String.class); Student student = studentClass.getDeclaredConstructor(String.class, int.class).newInstance("Tom", 18); hello.invoke(student); Object invoke = study.invoke(student); System.out.println(invoke); eat.invoke(student, "apple"); }
|
1
| Method.invoke(Object obj, Object... args)
|
通过class对象获取类的方法,但在使用方法时,要指名那个对象
类的成员变量
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Test public void FieldStudy() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Class<Student> studentClass = Student.class; Constructor<Student> declaredConstructor = studentClass.getDeclaredConstructor(String.class, int.class);
Student student = declaredConstructor.newInstance("Tom", 18); Field[] declaredFields = studentClass.getDeclaredFields();
declaredFields[0].setAccessible(true); declaredFields[1].setAccessible(true); declaredFields[0].set(student, "Jerry"); declaredFields[1].set(student, 20); System.out.println(student); System.out.println(declaredFields[0].get(student)); System.out.println(declaredFields[1].get(student));
}
|
注解
注解是提供一种为程序元素设置元数据的方法,理解起来还是一样的,程序元素就是指接口、类、属性、方法,这些都是属于程序的元素,那啥叫元数据呢?就是描述数据的数据(data about data)

注解的作用
- 作为特定标记,用于告诉编译器一些信息,例如@Override
- 编译时动态处理,如动态生成代码
- 运行时动态处理,作为额外信息的载体,如获取注解信息
注解的分类
1 2 3 4 5 6 7 8
| @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnn {
String value(); double aaa() default 100; String[] bbb(); }
|
- @Retention:从编写Java代码到运行主要周期为
源文件→ Class文件 → 运行时数据,@Retention则标注了自定义注解的信息要保留到哪个阶段,分别对应的value取值为SOURCE →CLASS→RUNTIME
- @Target:允许自定义注解标注在哪些Java元素上(类、方法、属性、局部属性、参数…)
通过反射获取注解
Demo
1 2 3 4 5 6 7 8 9
| @MyAnn(value = "Hello", aaa = 1, bbb = {"a", "b"}) public class Demo {
@MyAnn(value = "world", aaa = 2, bbb = {"c", "d"}) public void test(){
} }
|
MyAnn
1 2 3 4 5 6 7 8 9
| @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnn {
String value(); double aaa() default 100; String[] bbb(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Test public void parseClass() { Class<Demo> c = Demo.class; if (c.isAnnotationPresent(MyAnn.class)) { MyAnn declaredAnnotation = c.getDeclaredAnnotation(MyAnn.class);
double aaa = declaredAnnotation.aaa(); String[] bbb = declaredAnnotation.bbb(); String value = declaredAnnotation.value(); System.out.println(aaa); System.out.println(Arrays.toString(bbb)); System.out.println("value: " + value);
} else { System.out.println("No Annotation"); } }
|
编写MyTest以实现Test功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class Res { public void test01() { System.out.println("hello world 01"); }
@MyTest public void test02() { System.out.println("hello world 02"); }
public void test03() { System.out.println("hello world 03"); }
@MyTest public void test04() { System.out.println("hello world 04"); }
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException { Res res = new Res(); Class<? extends Res> aClass = res.getClass(); Method[] declaredMethods = aClass.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { if (declaredMethod.isAnnotationPresent(MyTest.class)) { declaredMethod.invoke(res); } } } }
|
注解原理初探
1 2 3 4 5 6 7 8
| @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnn {
String value(); double aaa() default 100; String[] bbb(); }
|
将上述代码的class文件反编译后
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com.example.Ann;
import java.lang.annotation.Annotation;
public interface MyAnnextends extends Annotation {
public abstract String value();
public abstract double aaa();
public abstract String[] bbb(); }
|
可以看出注解本质是一个接口