Java注解与反射 【b站狂神视频笔记】

概述

Annotation的作用

  • 不是程序本身,可以对程序作出结束(与注释comment无异)
  • 可以备其他程序(比如编译器)读取

Annotation的格式

  • 注解是以 @注释名 在代码中存在的,还可以添加一些参数值,例如 @SuppressWarnings(value = “unchecked”)

Annotation在哪里使用?

  • 可以附加在package,class,method,field上面,相当于添加额外的辅助信息,可以通过反射机制编程实现对这些元数据的访问

内置注解

  • @Override 定义在java.lang.Override 中,此注释只适用于修辞手法,表示一个方法声明打算重写超类中的另一个方法声明

  • @Deprecated 定义在java.lang.Deprecated 中,此注释可以用于修饰方法、属性、类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择

  • @SuppressWarnings 定义在 java.lang.SuppressWarnings 中,用来抑制编译时的警告信息,与前两个有所不同的是需要添加一个参数才能正常使用,这些参数都是定义好的

    @SuppressWarnings("all")
    @SuppressWarnings("unchecked")
    @SuppressWarnings(value = {"unchecked", "deprecation"})
    ...
    

元注解

元注解的作用就是负责注解其他注解,java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明

☆ @Target //用于描述注解的适用范围
☆ @Retention //表示在什么级别保存该注释信息,用于描述注解的生命周期(source < class  < RUNTIME)
@Document // 说明该注解将被包含在javadoc中
@Inherited // 说明子类可以继承父类中的该注解

自定义注解

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口

分析:

  1. @interface用来声明一个注解,格式 public @inteface 注解名 { content }
  2. 其中的每一个方法实际上是声明了一个配置参数
  3. 方法的名称就是参数的名称
  4. 返回值类型就是参数的类型(返回值只能是基本类型 class、String、 enum)
  5. 可以通过default来声明参数的默认值
  6. 如果只有一个参数成员,一般参数名为value
  7. 注解元素必须要有值,我们定义注解元素时,经常使用空字符串、0作为默认值
package com.company.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 自定义注解
public class test1 {
    // 注解可以显示赋值 如果没有默认值,就必须给注解赋值
    @MyAnnotation(name = "oho", age = 19)
    public void test(){

    }
}

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    // 注解的参数: 参数类型 + 参数名();
    // String value(); 此时上面的引用可以不需要 value = "xxx"
    String name() default "";
    int age() default 0;
    int id() default -1;// 如果默认值为-1,代表不存在

    String[] schoold() default "TshinghuaU";
}

反射机制

image-20210205160302755

image-20210205160611782

package com.company.annotation;

public class reflection {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c1 = Class.forName("com.company.annotation.User");
        System.out.println(c1);
        Class c2 = Class.forName("com.company.annotation.User");
        Class c3 = Class.forName("com.company.annotation.User");
        Class c4 = Class.forName("com.company.annotation.User");

        // 一个类在内存中只有一个class对象
        // 一个类被加载后,类的整个结构都会被封装在class对象中
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
        System.out.println(c4.hashCode());

    }
}
// 实体类 : pojo, entity
class User{
    private String name;
    private int id;
    private int age;

    public User() {
    }

    public User(String name, int id, int age) {
        this.name = name;
        this.id = id;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", age=" + age +
                '}';
    }
}


// 运行结果
/*
	class com.company.annotation.User
	284720968
	284720968
	284720968
*/

Class 类

image-20210205161444723

image-20210205161813044

image-20210205161824996

获取Class类的实例

image-20210205161949703

package com.company.annotation;

public class refClass {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println("this is :" + person.name);

        // 方式一: 通过对象获得
        Class c1 = person.getClass();
        System.out.println(c1);

        // 方式二: forname获得
        Class c2 = Class.forName("com.company.annotation.Student");
        System.out.println(c2);

        // 方式三:通过类名.class获得
        Class c3 = Student.class;
        System.out.println(c3);

        // 方法四 :基本内置类型的包装类都有一个Type属性
        Class c4 = Integer.TYPE;
        System.out.println(c4);

        // 获得父类类型
        Class c5 = c1.getSuperclass();
        System.out.println(c5);

    }
}

class Person{
    String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}
class Student extends Person{
    public Student(){
        this.name = "Stu";
    }
}class Teacher extends Person{
    public Teacher(){
        this.name = "Teac";
    }
}
package com.company.annotation;

import java.lang.annotation.ElementType;

// 所有类型的 Class
public class test2 {
    public static void main(String[] args) {
        Class c1 = Object.class; // 类
        Class c2 = Comparable.class; // 接口
        Class c3 = String[].class; // 一维数组
        Class c4 = int[][].class; // 二维数组
        Class c5 = Override.class; // 注解
        Class c6 = ElementType.class; // 枚举
        Class c7 = Integer.class; // 基本数据类型
        Class c8 = void.class; // void
        Class c9 = Class.class; // Class

        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);

        // 只要元素类型与维度一样,就是同一个Class
        int[] a = new int[10];
        int[] b = new int[100];
        System.out.println(a.getClass().hashCode());
        System.out.println(b.getClass().hashCode());
    }
}

Java 内存分析

image-20210206150037827

类初始化

image-20210206150543375

package com.company.annotation;
// 测试类声明时候会被初始化
public class test3 {
    static {
        System.out.println("Main 被加载");
    }
    public static void main(String[] args) throws ClassNotFoundException {
        // 1. 主动引用
        Son son = new Son();
        // 2. 反射也会产生主动引用
        Class.forName("com.company.annotation.Son");
        // 不会产生类的引用方法
        System.out.println(Son.b);
        Son[] array = new Son[100];
    }
}

class Father{
    static int b = 2;
    static {
        System.out.println("父类被加载");
    }
}
class Son extends Father{
    static {
        System.out.println("子类被加载");
        m = 300;

    }

    static  int m = 100;
    static final int M = 1;
}

获得运行时类的完整结构

package com.company.annotation;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

// 获取类的信息
public class test4 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("com.company.annotation.User");

        // 获得类的名字
        System.out.println(c1.getName()); // 获得包名 + 类名
        System.out.println(c1.getSimpleName());

        // 获得类的属性
        System.out.println("------------");
        Field[] fields = c1.getFields(); // 只能找到public属性

        fields = c1.getDeclaredFields(); // 找到全部的属性

        for (Field field : fields){
            System.out.println(field);
        }

        // 获得指定属性的值
        Field name = c1.getDeclaredField("name");
        System.out.println(name);

        // 获得类的方法
        System.out.println("------------");
        Method[] methods = c1.getMethods();// 获得本类及其父类的全部public方法
        for (Method method : methods){
            System.out.println("正常的:" + method);
        }
        methods = c1.getDeclaredMethods(); // 获得本类的全部方法
        for (Method method : methods){
            System.out.println("getDeclaredMethods:" + method);
        }

        // 获得指定方法
        // 重载
        Method getName = c1.getMethod("getName", null);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);

        // 获得指定的构造器
        System.out.println("--------------");
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor : constructors){
            System.out.println(constructor);
        }
        constructors  = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors){
            System.out.println(constructor);
        }

        // 获得指定的构造器
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        System.out.println("指定的:" + declaredConstructor);
    }
}

有了Class对象后续操作

image-20210207143717111

package com.company.annotation;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class test5 {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException, ClassNotFoundException {
        // 获得class对象
        Class c1 = Class.forName("com.company.annotation.User");

        // 构造一个对象
        User user = (User)c1.newInstance(); // 本质是调用了类的无参构造器
        System.out.println(user);

        // 通过构造器创建对象
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User user2 = (User)constructor.newInstance("快乐哥", 001, 20);
        System.out.println(user2);

        // 通过反射调用普通方法
        User user3 = (User)c1.newInstance();
        // 通过反射获取一个方法
        Method setName = c1.getDeclaredMethod("setName", String.class);

        // (对象, “方法的值”)
        setName.invoke(user3, "olao");
        System.out.println(user3.getName());

        // 通过反射操作属性
        System.out.println("---------------------");
        User user4 = (User)c1.newInstance();
        Field name = c1.getDeclaredField("name");

        //不能直接操作私有属性,我们需要关闭程序的安全监测,
        // 开启访问权限
        name.setAccessible(true);
        name.set(user4, "oila");
        System.out.println(user4.getName());
    }
}

反射操作泛型

image-20210207144938177

通过反射操作注解 (练习ORM)

image-20210207145409967

package com.company.annotation;

import java.lang.annotation.*;
import java.lang.reflect.Field;

public class orm {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.company.annotation.Stu");

        // 通过反射获得注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }

        // 获得注解的value的值
        TableStu tableStu = (TableStu)c1.getAnnotation(TableStu.class);
        String value = tableStu.value();
        System.out.println(value);


        // 获得类指定注解
        Field f = c1.getDeclaredField("name");
        FieldStu annotation = f.getAnnotation(FieldStu.class);
        System.out.println(annotation.columnName());
        System.out.println(annotation.length());
        System.out.println(annotation.type());
    }
}

@TableStu("db_stu")
class Stu{
    @FieldStu(columnName = "db_id", type = "int", length = 10)
    private int id;
    @FieldStu(columnName = "db_age", type = "int", length = 10)
    private int age;
    @FieldStu(columnName = "db_name", type = "varchar", length = 3)
    private String name;

    public Stu() {
    }

    public Stu(int id, int age, String name) {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Stu{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

// 类名的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface TableStu{
    String value();
}

// 属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldStu{
    String columnName();
    String type();
    int length();
}
posted @ 2021-02-05 16:33  CoderZjz  阅读(738)  评论(0编辑  收藏  举报