首页 > 技术文章 > 注解和反射的学习笔记(狂神说)

th11 2021-06-24 19:51 原文

注解与反射

## 学习自狂神说##

什么是注解

和注释一样,注解不是程序本身,而是对程序作出解释,而注解与注释不同的点在于,注解可以被其他程序比如编译器读取

2zGn0I.md.png

 

内置注解

2z8jl4.md.png

 @Override//重写注解
 @Deprecated//不推荐使用注解,可以使用但是又风险或者有更好的方式
 @SuppressWarnings//“镇压”警告注解

2z84yj.md.png

元注解

什么是元注解?

  • 元注解的作用就是负责注解其它注解,Java提供了3个meta-annotation类型,它们被用来提供对其它annotation类型的说明;

  • 这些类型可以在java.lang.annotation包中可以找到(@Target、@Retention、@Document、@Inherited);

元注解的作用:

  1. @Target:用来描述注解的使用范围(即:被描述的注解可以使用在什么地方);

  2. @Retention:表示什么级别保存该注解信息,用于描述注解的生命周期(SOURCE < CLASS < RUNTIME);

  3. @Document:说明该注解将被包含在javadoc中;

  4. @Inherited:说明子类可以继承父类中的该注解;

 package iss.demo05;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
  * 测试元注解
  */
 @MyAnnotation
 public class TestAnnotation {
    public static void main(String[] args) {
    }
 
    @MyAnnotation
    public void test(){}
 }
 
 /**
  * 自定义一个注解
  * Target表示有效的范围,目前设置的是在方法和类上都有效
  * Retention表示什么级别时保留该注解,目前设置的是运行级别
  */
 @Target(value = {ElementType.METHOD, ElementType.TYPE})
 @Retention(value = RetentionPolicy.RUNTIME)
 @interface MyAnnotation{
     
 
 }

自定义注解

 package iss.demo05;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 public class Test2 {
    //注解可以显示复制,如果没有默认值,就必须给注解复制
    @MyAnnotation1(schools = {"天软","天红"})
    public void test(){
    }
    //如果注解只有一个参数可以省略参数名(名字为value才可以)
    @MyAnnotation2("")
    public void test2(){
         
    }
 }
 
 @Target({ElementType.TYPE, ElementType.METHOD})
 @Retention(RetentionPolicy.RUNTIME)
 @interface MyAnnotation1{
    //注解的参数:类型+参数名()[default 默认值];
    String name() default "";
    int age() default 0;
    int id() default -1;
    String[] schools();
 }
 @Target({ElementType.TYPE,ElementType.METHOD})
 @Retention(RetentionPolicy.RUNTIME)
 @interface MyAnnotation2{
    //注解的参数:类型+参数名()[default 默认值];
    String[] value();
 }
 

2zwNk9.md.png

反射

动态语言和静态语言

 **动态语言**:在运行时可以改变其结构:例如新的函数、对象甚至代码可以被引进,已有的函数可以被删除或者是其他结构上的变化。通俗来说就是运行时代码可以根据一些条件来改变自身的结构。主要动态语言:Object-C、C#、JavaScript、PHP、Python等。

静态语言:与动态语言相对应的,运行时不能改变其结构,如Java、C、C++Java不是动态语言,但是java可以称为是“准动态语言”。即java有一定的动态性,可以利用反射机制获得类似动态语言的特性。Java的动态性使得编程时更加灵活。

 function f(){
  var x="var a=3;var b=5;x=a+b;";
  eval(x);
 }

反射是Java被视为动态语言的关键

RZeXy8.md.png

反射功能

RZmAyT.md.png

优缺点

RZmmTJ.md.png

API

RZmlSx.md.png

Class类的介绍

[RZmLN9.md.png

 

 

 package iss.demo06;
 
 //什么叫反射
 public class Demo04_Reflection {
    public static void main(String[] args) throws ClassNotFoundException {
        // 通过反射获取类的class对象
        Class<?> c = Class.forName("iss.demo06.User");
        System.out.println(c);
        Class<?> c1 = Class.forName("iss.demo06.User");
        Class<?> c2 = Class.forName("iss.demo06.User");
        Class<?> c3 = Class.forName("iss.demo06.User");
        // 一个类在内存中只有一个Class对象
        // 一个类被加载后,类的整个结构都会被封装在Class对象中
        /**
          * public native int hashCode();返回该对象的hash码值
          *     注:哈希值是根据哈希算法算出来的一个值,这个值跟地址值有关,但不是实际地址值。
          */
        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
    }
 }
 
 //实体类
 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;
    }
 }

RehRzD.md.png

 

Rehzes.png

获取class的实例

Re46mj.md.png

 package iss.demo06;
 
 //测试class类的创建方式有哪些
 public class Demo05_CreateClass {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println("这个人是:"+person.name);
 
        //方式一:通过对象查询
        Class c1 = person.getClass();
        System.out.println(c1.hashCode());
 
        //方式二:forname获得
        Class c2 = Class.forName("iss.demo06.Student");
        System.out.println(c2.hashCode());
 
        //方式三:通过类名.class获得
        Class c3 = Student.class;
        System.out.println(c3.hashCode());
 
        //方式四,基本类型的包装类都有一个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 = "学生";
    }
 }
 
 class Teacher extends Person {
    public Teacher() {
        this.name = "老师";
    }
 }

哪些类型可以有Class对象?  

  • class:外部类、成员(成员内部类、静态内部类),局部内部类,匿名内部类。

  • interface:接口

  • []:数组

  • enum:枚举

  • annotation:注解@interface

  • primitive type:基本数据类型

  • void

所有类型的class

 package iss.demo06;
 
 import java.lang.annotation.ElementType;
 
 //所有类型的Class
 public class Demo06_AllTypeClass {
    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());
    }
 }

类加载内存分析

ReXUWd.png

RejcB6.png

Rejf4e.png

 package iss.demo06;
 
 //类加载
 public class Demo07_ClassLoader {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(A.m);
        /**
          * 1. 加载到内存,会产生一个类对应Class对象
          * 2. 链接,连接结束后m=0
          * 3. 初始化
          * <clinit>(){
          *       System.out.println("A类静态代码块初始化");
          *       m = 300;
          *       m = 100;
          * }
          */
    }
 }
 
 class A {
    static {
        System.out.println("A类静态代码块初始化");
        m = 300;
    }
 
    static int m = 100;
 
    public A() {
        System.out.println("A类无参构造初始化");
    }
 }

RevCD0.png

分析类初始化

RexuWQ.png

 package iss.demo06;
 
 //测试类什么时候会初始化
 public class Demo08_Reference {
    static {
        System.out.println("Main类被加载");
    }
    public static void main(String[] args) throws ClassNotFoundException {
        // 1. 主动调用
        //Son son = new Son();
 
        // 2.反射也会产生主动引用
        Class.forName("iss.demo06.Son");
 
        //3.不会产生类的引用的方法
        //System.out.println(Son.b);
 
        //4.Son[] array = new Son[5];
         
        //5.System.out.println(Son.M);
    }M
 }
 
 class Father {
    static final int b = 2;
    static {
        System.out.println("父类被加载");
    }
 }
 class Son extends Father {
    static {
        System.out.println("子类被加载");
        m = 100;
    }M
    static int m = 300;
    static final int M = 1;
 }

类加载器

作用

RezA1J.png

RezWNT.png

ClassLoader

 package iss.demo06;
 
 //类加载器
 public class Demo09_ClassLoader {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取系统类的加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);
 
        //获取系统类加载器的父类加载器-->扩展类加载器   jre1.8.0_261\lib\ext
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);
 
        //获取扩展类加载器父类加载器-->根加载器(c/c++) jre1.8.0_261\lib\rt.jar
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1);
 
        //测试当前类是哪个加载器加载的
        ClassLoader classLoader = Class.forName("iss.demo06.Demo09_ClassLoader").getClassLoader();
        System.out.println(classLoader);
 
        //测试JDK内置的类是谁加载的
        classLoader = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader);
 
        //如何获得系统类加载器可以加载的路径
        System.out.println(System.getProperty("java.class.path"));
 /*
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\charsets.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\deploy.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\access-bridge-64.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\cldrdata.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\dnsns.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\jaccess.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\jfxrt.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\localedata.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\nashorn.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\sunec.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\sunjce_provider.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\sunmscapi.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\sunpkcs11.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\ext\zipfs.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\javaws.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\jce.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\jfr.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\jfxswt.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\jsse.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\management-agent.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\plugin.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\resources.jar;
        D:\Program Files\Java\jdk1.8.0_261\jre\lib\rt.jar;
        D:\Users\Administrator\IdeaProjects\untitled\out\production\untitled;
        D:\Program Files\JetBrains\IntelliJ IDEA 2019.3.1\lib\idea_rt.jar
 
 */
 
 
        //双亲委派机制 检测安全性 你写的类和跟加载器一样的不会用你写的类
        //java.lang.String -->往上推
 
    }
 }

获取类的运行时结构

概念

RmVpYn.png

代码

 package iss.demo06;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 
 //获取类的信息
 public class Demo10_ClassInfo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("iss.demo06.User");
        User user = new User();
        c1 = user.getClass();
 
        //获得类的名字
        System.out.println(c1.getName());// 获得包名 + 类名
        System.out.println(c1.getSimpleName());// 获得类名
 
        System.out.println("=======================");
 
        //获得类的属性
        Field[] fields = c1.getFields();//只能找到public属性
        for (Field field : fields) {
            System.out.println("getFields:" + field);
        }
        fields = c1.getDeclaredFields();//找到全部的属性
        for (Field field : fields) {
            System.out.println("getDeclaredFields:" + 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("getMethods:" + method);
        }
        methods = c1.getDeclaredMethods(); //获得本类的所有方法(包括私有)
        for (Method method : methods) {
            System.out.println("getDeclaredMethods:" + method);
        }
        System.out.println("=======================");
 
        //获得指定的方法
        //重载
        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("getConstructors:" + constructor);
        }
        constructors = c1.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            System.out.println("getDeclaredConstructors:" + constructor);
        }
 
 
        //获得指定的构造器
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        System.out.println("指定构造器" + declaredConstructor);
 
    }
 }
 
 
 //********以下笔记**************
 
 Class c1 = Class.forName(“iss.demo06.User”); //获取当前对象的Class
 
 //获得类的名字
 c1.getName();// 获得包名 + 类名
 c1.getSimpleName();// 获得类名
 
 //获得类的方法
 c1.getMethods(); //获得本类及父类的全部public方法
 c1.getDeclaredMethods(); //获得本类的所有方法
 c1.getMethod(“getName”, null);//获得指定的方法
 
 //获得类的构造器
 c1.getConstructors();
 c1.getDeclaredConstructors();
 c1.getDeclaredConstructor(String.class, int.class, int.class);//获得指定的构造器

动态创建对象执行方法

newInstance()

RQu8gg.png

getDeclaredConstructor

 package com.iss.demo06;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
 //动态创建对象,通过反射
 public class Demo08 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
              //获得class对象
        Class c1 = Class.forName("com.iss.demo06.User");
         
                //创建一个对象
        System.out.println("============================");
        User user = (User)c1.newInstance();//本质是调用了类的无参构造器
        System.out.println(user);
         
                //通过构造器创建对象
        System.out.println("============================");
        Constructor constructor = c1.getDeclaredConstructor(String.class,int.class,int.class);
        User user2 = (User)constructor.newInstance("天天",22,55);
        System.out.println(user2);
         
        //通过反射调用普通方法
        //通过反射获取一个方法
        System.out.println("============================");
        Method setName = c1.getDeclaredMethod("setName",String.class);
         
        //invoke:激活的意思
        //参数:对象,方法的值
        setName.invoke(user,"老婆");
        System.out.println(user.getName());
        System.out.println("============================");
         
        //通过反射操作属性
        User user3 = (User)c1.newInstance();
        Field name = c1.getDeclaredField("name");
         
        //不能直接操作私有属性,我们需要关闭程序的安全监测,属性或方法的setAccessible(true)
        name.setAccessible(true);
        name.set(user3,"苏苏");
        System.out.println(user3.getName());
    }
 }

invokeRQM9fK.png

setAccessible(true)RQKvwR.png

性能对比分析

RQMl6g.png

 package com.iss.demo06;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 
 public class Demo09 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        test1();
        test2();
        test3();
    }
 
    public static void test1() {
        User user = new User();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            user.getName();
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start + "ms");
    }
 
    public static void test2() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getDeclaredMethod("getName", null);
 
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user, null);
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start + "ms");
    }
 
    public static void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        User user = new User();
        Class c1 = user.getClass();
        Method getName = c1.getDeclaredMethod("getName", null);
        getName.setAccessible(true);
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000000000; i++) {
            getName.invoke(user, null);
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start + "ms");
    }
 }

反射操作泛型

RQQr28.png

 package com.iss.demo06;
 
 import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.util.List;
 import java.util.Map;
 
 public class Demo10 {
    public void test01(Map<String, User> map, List<User> list) {
        System.out.println("test01");
    }
 
    public Map<String, User> test02() {
        System.out.println("test02");
        return null;
    }
 
    public static void main(String[] args) throws NoSuchMethodException {
        Method method = Demo10.class.getMethod("test01", Map.class, List.class);
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            System.out.println("参数范型" + genericParameterType);
            if (genericParameterType instanceof ParameterizedType) {
                Type[] actualTypeAnguments = ((ParameterizedType) (ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeAngument : actualTypeAnguments) {
                    System.out.println("实际参数范型" + actualTypeAngument);
                }
            }
        }
        Method method1 = Demo10.class.getMethod("test02", null);
        Type getGenericReturnType = method1.getGenericReturnType();
        if (getGenericReturnType instanceof ParameterizedType) {
            Type[] actualTypeArguments = ((ParameterizedType) getGenericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println("返回值范型" + actualTypeArgument);
            }
        }
    }
 }

获取注解信息

 

ORMRQlkdA.png

getAnnotation

 package com.iss.demo06;
 
 import com.sun.xml.internal.ws.api.ha.StickyFeature;
 
 import java.lang.annotation.*;
 import java.lang.reflect.Field;
 import java.security.cert.CRLReason;
 
 public class Demo11 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class c1 = Class.forName("com.iss.demo06.Student");
 
 
        //通过反射获取注解
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);//@com.reflection.Table(value=db_student)
        }
 
        //获得注解中的value值
        Table table = (Table) c1.getAnnotation(Table.class);
        String value = table.value();
        System.out.println(value);//db_student
 
        //获得类指定的注解
        Field f = c1.getDeclaredField("name");
        Filed annotation = f.getAnnotation(Filed.class);
        System.out.println(annotation.columnName());//db_name
        System.out.println(annotation.length());//3
        System.out.println(annotation.type());//varchar
    }
 }
 
 @Table("db_student")
 class Student {
    @Filed(columnName = "db_id", type = "int", length = 10)
    private int id;
    @Filed(columnName = "db_age", type = "int", length = 10)
    private int age;
    @Filed(columnName = "db_name", type = "varchar", length = 3)
    private String name;
 
    public Student() {
    }
 
    public Student(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;
    }
 }
 
 //类名的注解
 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)
 @interface Table {
    String value();
 }
 
 @Target(ElementType.FIELD)
 @Retention(RetentionPolicy.RUNTIME)
 @interface Filed {
    String columnName();
 
    String type();
 
    int length();
 }

推荐阅读