注解与反射

01 注解学习

1
注解是一种代码级别的说明,注释和注解一个最大的区别就是,当你代码哪里写错了,注解会报错
  • 我们以前常用的一个注解,@Override 指的是重写

001 内置注解

1
2
3
@Override 指的是重写
@Deprecated 修饰方法,指不鼓励使用这样的元素
@SuppressWarnings 用来抑制警告信息

002 元注解

001 @Retention

  • 翻译是保留的意思,这个注解的意思其实就是在什么阶段去保留
  • @Retention(RetentionPolicy.RUNTIME) 的作用是确保注解在运行时可用,基本上使用这个
  • @Retention(RetentionPolicy.SOURCE) 的作用是在源码时保留
  • @Retention(RetentionPolicy.CLASS) 的作用是在CLASS时可用

002 @Target

  • 这个的意思是指作用域在哪里
  • @Target(ElementType.METHOD) 作用在方法上
  • @Target(ElementType.TYPE) 作用在类型上
  • @Target(ElementType.LOCA_VARIABLE) 作用在变量上
  • 就可以让这个注解去注解别人
image-20250324151157511
  • 可以像这样多放:@Target(value= {ElementType.METHOD,ElementType.TYPE})

003 @Documented

表示是否将我们的注解生成在Javadoc中

004 @Inherited

子类可以继承父类的注解

003 自定义注解

image-20250324152015245

eg:

1
2
3
4
5
6
7
8
9
10
11
12
public class test02 {
@MyAnnotation(age=0)
public void test(){
}
}

@Target(value= {ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
String name() default "";
int age();
}

用value的话上面可以省略value:

1
2
3
4
5
6
7
8
9
10
11
public class test02 {
@MyAnnotation("123")
public void test(){
}
}

@Target(value= {ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
String value();
}

02 反射学习

image-20250325075934441 image-20250325075947292

001 通过反射获取类的class对象

实体类:pojo,entity

  • 一个类在内存中只有一个Class对象
  • 一个类被加载后,类的整个结构都会被封装在Class对象中
image-20250325090858411
1
2
3
4
5
6
7
8
9
// forname获得
Class cl = Class.forName("reflection.User");

// 创建对象获得
User user=new User();
Class c2 = user.getClass();

// 通过类名.class获得
Class<User> c3 = User.class;

002 class类常用方法

image-20250325091139387

03 获得类的信息

001 获取包名+类名 或 类名

  • 具体代码
1
2
System.out.println(cl.getName());
System.out.println(cl.getSimpleName());

可以像这样来查询不知道的包名

1
2
3
User user=new User();
Class c2 = user.getClass();
System.out.println(c2.getName());

002 获取类的属性

  • Field[] fields = cl.getFields();只能找到public属性
1
2
3
4
Field[] fields = cl.getFields();
for (Field field : fields) {
System.out.println(field);
}
  • fields = cl.getDeclaredFields();能找到全部属性
1
2
3
4
fields = cl.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}

这两者里面加上具体内容如 fields = cl.getDeclaredFields(name);

获取指定属性的值

003 获得类的方法

  • Method[] methods=cl.getMethods(); 获得本类和父类的public方法
1
2
3
4
Method[] methods=cl.getMethods();
for (Method method : methods) {
System.out.println("正常的"+ method);
}
  • methods=cl.getDeclaredMethods(); 获得本类所有方法
1
2
3
4
methods=cl.getDeclaredMethods();
for (Method method : methods) {
System.out.println("本类的"+ method);
}
  • 获得指定方法
1
2
Method getName = cl.getMethod("getName", null);
Method setName = cl.getMethod("setName", String.class);

004 获取类的构造方法

  • 获取public构造方法

    1
    2
    3
    4
    Constructor[] constructors = cl.getConstructors();
    for (Constructor constructor : constructors) {
    System.out.println(constructor);
    }
  • 获取构造方法

    1
    2
    3
    4
    Constructor[] constructors = cl.getDeclaredConstructors();
    for (Constructor constructor : constructors) {
    System.out.println(constructor);
    }
  • 获得指定方法

    1
    Constructor constructor = cl.getDeclaredConstructor(String.class,int.class);

005 动态创建对象

(1) 无参/有参创建对象

  • 这两者的输出是相等的
1
2
3
4
5
6
7
8
9
//获得class对象
Class<?> c1 = Class.forName("reflection.User");

//构造一个对象
User user = (User) c1.newInstance(); //无参
System.out.println(user);

User user2=new User();
System.out.println(user2);
  • 有参则需要通过构造器创建对象

    1
    2
    3
    4
    //获得构造器
    Constructor<?> declaredConstructor = c1.getDeclaredConstructor(String.class, int.class);
    User user2 = (User) declaredConstructor.newInstance("cl", 1);
    System.out.println(user2);

    输出

    1
    User{name = cl, age = 1}

(2) 通过反射调用普通方法

1
2
3
4
5
6
7
8
9
//构造一个对象
User user = (User) c1.newInstance();
System.out.println(user);
//获取一个方法
Method setName = c1.getDeclaredMethod("setName", String.class);
//激活方法
setName.invoke(user,"cl");
//调用
System.out.println(user.getName());

(3) 通过反射操作属性

  • 我们这样用他是会报错的,因为私有属性不让被set
1
2
3
Field name = c1.getDeclaredField("name");

name.set(user,"cl");
  • 因此我们需要用name.setAccessible(true);来关闭程序的安全检测

    1
    2
    name.setAccessible(true);
    name.set(user,"cll");

04 注解和反射

image-20250325171032120
  • 建立两个注解,一个是类名的注解,另一个是属性的注解
image-20250326091140637
  • 把我们的类名和属性加上注解

    image-20250326091345098
  • 创建类的class对象,通过反射获取类名的注解

    image-20250326091646876
  • 获得指定类名的value值

    image-20250326091754873
  • 获得指定属性的注解

    image-20250326091928944

学习视频:【【狂神说Java】注解和反射】 https://www.bilibili.com/video/BV1p4411P7V3/?p=4&share_source=copy_web&vd_source=b2941ac430d9a6b02b476a1e91c98c42