JAVA----反射与注解入门学习

写在最前面

这篇笔记是看秦老师的 注解和反射 视频写的, 建议去看视频学习, 能掌握更多的内容

B站链接在此:

视频链接https://www.bilibili.com/video/BV1p4411P7V3

主页链接https://space.bilibili.com/95256449

在学习注解之前,只知道@Test 的 Junit 包 , 发现后面要学习的Spring 等框架需要用到, 就来补一课
下面的内容可以作为笔记参考,直接看文档可能观感不佳, 视频中的大部分代码都有写,适合边看视频边实际操作,一共两个小时也不算太长。

注解

注解入门

什么是注解

image-20200730103754446

内置注解

image-20200730105008727

@Override 重写父类方法

    @Override
    public String toString() {
        return super.toString();
    }

@Deprecated 表示, 不推荐使用 , 但是可以使用 ,或者存在更好的方法 , 在IDEA中使用这个元素时有删除线提醒

image-20200730110449162

@SuppressWarnings 抑制编译时的警告信息

image-20200730110939293

image-20200730111102861

元注解

image-20200730111246408

元注解作用是 注解其他的注解 元注解有以下几种:

  1. @Target 指定注解的使用范围
  2. @Retention 描述注解的生命周期
    • SOURCE: 在源文件中有效
    • CLASS : 在类文件中有效
    • RUNTIME: 在运行时有效
  3. @Documented 说明注解将被包含在javadoc中
  4. @Inherited 说明子类可以继承父类中的该注解

详细说明如下:


注解声明

@Target(value = {ElementType.METHOD,ElementType.TYPE})//指定作用域为 方法(METHOD) 或者 类(TYPE)
@Retention(value = RetentionPolicy.RUNTIME) //表示注解在什么时候有效
public @interface MyAnnotation{
		// 具体的内容 , 在下面的自定义注解中解释
        }

@Target

**例子: **

@Target(value = {ElementType.METHOD,ElementType.TYPE})

通过设置value的值, 可以指定该注解的作用范围 ,各种值如下:

    /** Class, interface (including annotation type), or enum declaration */
    TYPE,    //类 接口 等

    /** Field declaration (includes enum constants) */
    FIELD,  

    /** Method declaration */
    METHOD,   //方法

    /** Formal parameter declaration */
    PARAMETER,   // 参数

    /** Constructor declaration */
    CONSTRUCTOR,  // 构造器

    /** Local variable declaration */
    LOCAL_VARIABLE,  // 本地变量

    /** Annotation type declaration */
    ANNOTATION_TYPE,  //注解

    /** Package declaration */
    PACKAGE,   //包

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE


@Retention

使用举例:

@Retention(value = RetentionPolicy.RUNTIME) //设置作用时间为运行时

同样是通过设置value的值来指定生命周期 , 值如下

    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE, 

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME

**注:生命周期大小 runtime>class>sources **

自定义注解

image-20200730114009118

自定义注解 使用public @ interface 来声明

  1. 自定义注解中的每一个方法 实际上是声明的配置参数 ,在使用该注解的时候需要指定该参数的值, 不然会报错
  2. 方法的名称就是参数的名称

image-20200730114602715

image-20200730115022689

可以通过default来声明参数的默认值 ,这样调用时 可以不指定参数 ,也可以显示的赋值

image-20200730114910826

规范: 如果参数成员只有一个 ,推荐名为value

反射机制

image-20200730115640692

Java反射机制概述

在了解反射之前可以先理解一下静态和动态语言

  1. 动态语言是可以在运势是改变其结构的语言 ( 边编译边执行)。
  2. 动态语言在运行时无法改变结构 ( 一次编译 ,永久运行)。
  3. java通过引入反射的机制, 使得自身具有了一定的动态性。

image-20200730122039082

反射

  1. 借助反射的API 可以获取的任何内部信息 , 并且能够直接操作任意对象的内部属性以及方法。
  2. 类加载后 , 在堆内存的方法区中就产生了一个Class类型的对象( 一个类只有一个Class对象), 这个类就包含了完整的类的结构信息
  3. 如下图的最后流程图 , 通过反射的机制 , 可以创建一个对象, 通过对象 获取类 ,

image-20200730122412169

反射机制研究和应用

image-20200730124223007

反射优点和缺点:

在实现了动态创建对象和编译的时候 , 损失了一部分性能

image-20200730124320189

代码测试

package com.qwrdxer.reflection;

public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //通过反射获取类的class对象
            //可能找不到类, 需要抛出异常
        Class c1=Class.forName("com.qwrdxer.reflection.User");
    }
}

//定义一个实体类

class User{
    private String name;
    private int id;
    private int 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() {
        final StringBuilder sb = new StringBuilder("{");
        sb.append("\"name\":\"")
                .append(name).append('\"');
        sb.append(",\"id\":")
                .append(id);
        sb.append(",\"age\":")
                .append(age);
        sb.append('}');
        return sb.toString();
    }

}

通过Class c1=Class.forName(“com.qwrdxer.reflection.User”); 来加载class对象 ,可以获取这个类的所有内部信息

image-20200730125234509

理解Class类并获取Class实例

image-20200730125513337

常用的方法:

image-20200730125639981

获取Class类的实例方法

image-20200730125724405

具有Class对象 的类型

image-20200730130305268

        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

在数组中 , 只要元素类型 和维度一样,class一样

类的加载与ClassLoader

image-20200730131015021

类的加载过程

image-20200730131038923

类的加载与ClassLoader理解

image-20200730131114309

测试代码

package com.qwrdxer.reflection;

public class Test05 {
    public static void main(String[] args) {
        A a=new A();
        System.out.println(A.m);
    }
}

class A{
    static {
        System.out.println("A类静态代码块初始化");
        m=200;
    }
    static  int m=100;

    public A(){
        System.out.println("A类的无参数构造初始化");
    }
}

运行结果

image-20200730132356572

分析

  1. 首先将类加载到方法区 ,在堆中, 生成class对象

  2. 链接 ,结束后m=0

  3. 初始化

    • System.out.println(“A类静态代码块初始化”);
      m=200;
    • m=100;

什么时候发生类的初始化

image-20200730133240154

代码如下

package com.qwrdxer.reflection;

public class Test06 {
    static {
        System.out.println("Main类  加载");

    }

    public static void main(String[] args) throws ClassNotFoundException {
        //1. 主动引用
        Son son=new Son();
        //输出结果:
        //Main类  加载
        //父类   加载
        //子类    加载

        //2. 反射 也会产生主动引用
        Class.forName("com.qwrdxer.reflection.Test06");
        //输出结果:
        //Main类  加载
        //父类   加载
        //子类    加载


        //不会产生类的引用的方法
        System.out.println(Son.b);//父类静态变量
        Son[] array=new Son[4];//创建数组
        System.out.println(Son.M);//常量
    }
}

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

类加载器的作用

image-20200730134934211

image-20200730135501212

image-20200730135813904

根加载器是C++编写的,无法直接获取 返回null

package com.qwrdxer.reflection;

public class Test07 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取系统类的加载器
        ClassLoader systemClassLoader=ClassLoader.getSystemClassLoader();
        //获取系统类加载器的父类加载器 --> 扩展类加载器
        ClassLoader parent =systemClassLoader.getParent();

        //获取扩展类加载器的父类加载器---> 根加载器(**根加载器是C++编写的,无法直接获取 返回null**)
        ClassLoader parent1=parent.getParent();

        //测试当前类加载器是由哪个加载器加载的
        ClassLoader classLoader=Class.forName("com.qwrdxer.reflection.Test07").getClassLoader();
        System.out.println(classLoader);
            //sun.misc.Launcher$AppClassLoader@18b4aac2

        //测试JDK内置的类是谁加载的
        classLoader =Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader);
            //null
        
        //获取系统类加载器可以加载的路径
        for(String s:System.getProperty("java.class.path").split(";")){
            System.out.println(s);
        }
		 //C:\Program Files\Java\jdk1.8.0_251\jre\lib\charsets.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\deploy.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\ext\access-bridge-64.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\ext\cldrdata.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\ext\dnsns.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\ext\jaccess.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\ext\jfxrt.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\ext\localedata.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\ext\nashorn.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\ext\sunec.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\ext\sunjce_provider.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\ext\sunmscapi.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\ext\sunpkcs11.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\ext\zipfs.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\javaws.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\jce.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\jfr.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\jfxswt.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\jsse.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\management-agent.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\plugin.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\resources.jar
        //C:\Program Files\Java\jdk1.8.0_251\jre\lib\rt.jar
        //E:\平时写的代码\Java\注解和反射\out\production\注解和反射
        //G:\develop\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar
    }
}

获取运行时类的完整结构

image-20200730145217172

package com.qwrdxer.reflection;

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

public class Test08 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1=Class.forName("com.qwrdxer.reflection.User");
        System.out.println(c1.getName());//获取包名+类名
        System.out.println(c1.getSimpleName());//获得类名


        //获得类的属性
        //Field[] fields = c1.getFields();  只能找到public的属性
        Field[] fields = c1.getDeclaredFields(); // 能找到全部属性
        for (Field field : fields) {
            System.out.println(field);
        }
            //获得指定属性的值
        Field name = c1.getDeclaredField("name");

        //获得类的方法
        Method[] methods = c1.getMethods();//获得本类和父类的全部public方法
        for (Method method : methods) {
            System.out.println(method);
        }
        Method[] declaredMethods = c1.getDeclaredMethods();//获得本类所有的方法
        for (Method method : methods) {
            System.out.println(method);
        }

        //获得类方法
        Method getname=c1.getMethod("getName",null);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getname);

        //获得构造器
        Constructor[] constructors = c1.getConstructors();
        Constructor[] declaredConstructors = c1.getDeclaredConstructors();

            //获得指定的构造器
        Constructor constructor = c1.getConstructor(String.class,int.class,int.class);
    }
}

调用运行时类的指定结构

image-20200730185335908

通过反射动态创建对象( 无参)

package com.qwrdxer.reflection;

//通过反射动态创建对象
public class Test09 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class c1=Class.forName("com.qwrdxer.reflection.User");

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

}

有参构造器

        //通过构造器创建对象
        Constructor constructor = c1.getConstructor(String.class, int.class, int.class);
        User user2 = (User)constructor.newInstance("test", 001, 18);

通过反射调用普通方法

image-20200730191228185

        //通过反射调用普通方法
        User user3=(User)c1.newInstance();
            //通过反射获取方法
        Method setName=c1.getMethod("setName", String.class);
            //invoke 激活  第一个参数为对象 ,第二个参数为要传递的参数值
        setName.invoke(user3,"qwrdxer");
        System.out.println(user3.toString());

image-20200730191254020

通过反射操作属性

        //通过反射操作属性
        User user4=(User)c1.newInstance();
        Field name = c1.getDeclaredField("name");
            //如果属性是私有的, 需要显示的设置可以访问(关闭程序的安全检测)
        name.setAccessible(true);
            //使用set方法设置
        name.set(user4,"qwrdxer2");
        System.out.println(user4);

setAccessible 性能分析

image-20200730191423792

package com.qwrdxer.reflection;

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

public class test10 {
    public static void main(String[] args) throws NoSuchMethodException, ClassNotFoundException, InvocationTargetException, IllegalAccessException {
     User user=new User();
     long startTime =System.currentTimeMillis();
     for(int i=0;i<10000000;i++){
         user.getAge();
     }
     long endTime =System.currentTimeMillis();
     System.out.println("使用普通方式执行方法:"+(endTime-startTime)+"ms");

     //反射的方式
        Class c1=Class.forName("com.qwrdxer.reflection.User");
        Method getName=c1.getMethod("getName");
        User user2=new User();
        long startTime2 =System.currentTimeMillis();
        for(int i=0;i<10000000;i++){
            getName.invoke(user2,null);
        }
        long endTime2 =System.currentTimeMillis();
        System.out.println("使用反射方式执行方法:"+(endTime2-startTime2)+"ms");

      //反射方式 , 关闭检测
        Class c2=Class.forName("com.qwrdxer.reflection.User");
        Method getName2=c2.getMethod("getName");
        User user3=new User();
        getName2.setAccessible(true);//关闭检测
        long startTime3 =System.currentTimeMillis();
        for(int i=0;i<10000000;i++){
            getName2.invoke(user3,null);
        }
        long endTime3 =System.currentTimeMillis();
        System.out.println("使用反射方式(关闭检测)执行方法:"+(endTime3-startTime3)+"ms");
    }
}

image-20200730192335791

获取泛型信息

image-20200730192422570

代码如下

package com.qwrdxer.reflection;

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 Test11 {
    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 test01 = Test11.class.getMethod("test01", Map.class, List.class);
        Type[] genericParameterTypes = test01.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            System.out.println("#"+genericParameterType);
            if(genericParameterType instanceof ParameterizedType){
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }

        }
    }
}

输出:
#java.util.Map<java.lang.String, com.qwrdxer.reflection.User>
class java.lang.String
class com.qwrdxer.reflection.User
#java.util.List<com.qwrdxer.reflection.User>
class com.qwrdxer.reflection.User

反射操作注解

image-20200730225529696

package com.qwrdxer.reflection;

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

//练习反射操作注解
public class Test13 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class<?> aClass = Class.forName("com.qwrdxer.reflection.Student2");

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

        //获得注解中Value的值
        Tableau annotation = aClass.getAnnotation(Tableau.class);
        String value = annotation.value();
        System.out.println(value);

        //获得类指定的注解
        Field[] fields = aClass.getDeclaredFields();
        for (Field field : fields) {
            Fieldau annotation1 = field.getAnnotation(Fieldau.class);
            System.out.println(annotation1.columnName());
            System.out.println(annotation1.length());
            System.out.println(annotation1.type());
        }
//        Field name = aClass.getDeclaredField("name");
//        Fieldau annotation1 = name.getAnnotation(Fieldau.class);
//        System.out.println(annotation1.type());
//        System.out.println(annotation1.length());
//        System.out.println(annotation1.columnName());
    }
}
@Tableau("db_student")
class Student2{
    @Fieldau(columnName = "db_id",type = "int",length = 10)
    private int id;
    @Fieldau(columnName = "db_age",type = "int",length = 10)
    private int age;
    @Fieldau(columnName = "db_name",type = "String",length = 10)
    private String name;

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

    public Student2() {
    }

    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 new StringJoiner(", ", Student2.class.getSimpleName() + "[", "]")
                .add("id=" + id)
                .add("age=" + age)
                .add("name='" + name + "'")
                .toString();
    }
}


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

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Fieldau{
    String columnName();
    String type();
    int length();
}

etId(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 new StringJoiner(", ", Student2.class.getSimpleName() + "[", "]")
            .add("id=" + id)
            .add("age=" + age)
            .add("name='" + name + "'")
            .toString();
}

}

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

//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Fieldau{
String columnName();
String type();
int length();
}


©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页