关于Java中泛型、反射和注解的扫盲篇

泛型

泛型概念

  泛型是在 JDK1.5 之后引入的,旨在让我们写出更加通用化,更加灵活的代码。通用化的手段在于让数据类型变得参数化,定义泛型时,对应的数据类型是不确定的,泛型方法被调用时,会指定具体类型,其核心目标是为了解决容器类型在编译时安全检查的问题。
  泛型:一般用在类、方法、接口中,叫做泛型类、泛型接口、泛型方法

泛型的使用

 package demo.generic;

import lombok.Data;

/**

  • 泛型类的定义

  • @param <T>
    */
    @Data
    public class GenericClassExample<T> {
    //member 这个成员变量的类型为 T,T 的类型由外部指定
    private T member;
    // 泛型类的构造方法形参 member 的类型也为 T,T 的类型由外部指定
    public GenericClassExample(T member) {
    this.member = member;
    }

    // 泛型类中也可以定义普通方法,普通方法的参数也为泛型
    public T handleSomething(T target) {
    return target;
    }
    }

  1. 泛型的参数不支持基本类型;泛型相关的信息不会进入到运行时阶段
     package demo.generic;
    

    public class GenericDemo {
    public static void main(String[] args) {
    GenericClassExample<String> strExample = new GenericClassExample<>("abc");
    GenericClassExample<Integer> intExample = new GenericClassExample<>(123);
    System.out.println(strExample.getClass()); // 打印泛型类的类型
    System.out.println(intExample.getClass()); // 打印泛型类的类型
    }
    }

    // *运行结果
    //class demo.generic.GenericClassExample
    //class demo.generic.GenericClassExample
    // 我们可以从运行结果看出 strExample 和 intExample 的类型是一样的,因此泛型类的类型约束只在编译时有效

  2. 能否在泛型里面使用具备继承关系的类?
    • 使用通配符 ?,但是会使得泛型的类型检查失去意义
    • 给泛型加入上边界 <? extends E>
    • 给泛型加入下边界 <? super E>
      package demo.generic;
      

      public class GenericDemo {

      <span class="hljs-comment">//给泛型加如上边界 ? extends E, 泛型类型必须是E的类型或其子类</span>
      <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">void</span> <span class="hljs-title function_">handleMember</span>(<span class="hljs-params">GenericClassExample&lt;? <span class="hljs-keyword">extends</span> <span class="hljs-built_in">Number</span>&gt; integerExample</span>) {
          <span class="hljs-title class_">Integer</span> result = (<span class="hljs-title class_">Integer</span>) integerExample.<span class="hljs-title function_">getMember</span>() + <span class="hljs-number">100</span>;
          <span class="hljs-title class_">System</span>.<span class="hljs-property">out</span>.<span class="hljs-title function_">println</span>(<span class="hljs-string">"result is "</span> + result);
      }
      
      <span class="hljs-comment">//给泛型加入下边界 ? super E ,泛型类型必须是E的类型或其父类</span>
      <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">void</span> <span class="hljs-title function_">handleSuperMember</span>(<span class="hljs-params">GenericClassExample&lt;? <span class="hljs-variable language_">super</span> Integer&gt; integerExample</span>) {
          <span class="hljs-title class_">Integer</span> result = (<span class="hljs-title class_">Integer</span>) integerExample.<span class="hljs-title function_">getMember</span>() + <span class="hljs-number">100</span>;
          <span class="hljs-title class_">System</span>.<span class="hljs-property">out</span>.<span class="hljs-title function_">println</span>(<span class="hljs-string">"result is "</span> + result);
      }
      
      <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-built_in">void</span> <span class="hljs-title function_">main</span>(<span class="hljs-params"><span class="hljs-built_in">String</span>[] args</span>) {
          <span class="hljs-title class_">GenericClassExample</span>&lt;<span class="hljs-title class_">String</span>&gt; strExample = <span class="hljs-keyword">new</span> <span class="hljs-title class_">GenericClassExample</span>&lt;&gt;(<span class="hljs-string">"abc"</span>);
          <span class="hljs-title class_">GenericClassExample</span>&lt;<span class="hljs-title class_">Integer</span>&gt; integerExample = <span class="hljs-keyword">new</span> <span class="hljs-title class_">GenericClassExample</span>&lt;&gt;(<span class="hljs-number">123</span>);
          <span class="hljs-title class_">GenericClassExample</span>&lt;<span class="hljs-title class_">Number</span>&gt; numberExample = <span class="hljs-keyword">new</span> <span class="hljs-title class_">GenericClassExample</span>&lt;&gt;(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Integer</span>(<span class="hljs-number">123</span>));
      

      // handleMember(strExample); // 编译会报错,因为 String 不是 Number 的子类
      handleMember(integerExample); // 不会报错,因为 Integer 是 Number 的子类
      handleSuperMember(integerExample); // 不会报错,因为 Integer 和泛型类的类型相同
      handleSuperMember(numberExample ); // 不会报错,因为 Number 是泛型类 Integer 的父类
      }
      }

  3. 泛型方法: 使用泛型标识符标识的方法
    // <E> 泛型标识符
    public static <E> void printArray(E[] array) {
        for(E element : array){
            System.out.printf("%s",element);
        }
    }
    
  4. 泛型字母的含义
    • E - Element: 在集合中使用,因为集合中存放的是元素
    • T - Type: Java 类
    • K - Key: 键
    • V - Value: 值
    • N - Number: 数值类型

反射

反射的概念及作用

  反射允许程序在运行时来进行自我检查并且对内部的成员进行操作。反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。

  1. 反射机制的作用
    • 在运行时判断任意一个对象所属的类
    • 在运行时获取类的对象
    • 在运行时访问 java 对象的属性、方法、构造方法等
  2. java.lang.reflect 类库里面主要的类
    • Field: 表示类中的成员变量
    • Method: 表示类中的方法
    • Constructor: 表示类的构造方法
    • Array: 该类提供了动态创建数组和访问数组元素的静态方法
  3. 反射依赖的 Class:用来表示运行时类型信息的对应类
    • 每个类都有唯一一个与之相应的 Class 对象
    • Class 类为类类型,而 Class 对象为类类型对象
    • Class 类的特点
      • Class 类也是类的一种,class 则是关键字
      • Class 类只有一个私有的构造函数,只有 JVM 能够创建 Class 类的实例
      • JVM 中只有唯一一个和类相对应的 Class 对象来描述其类型信息
    • 获取 CLass 对象的三种方式
      • Object -> getClass()
      • 任何数据类型(包括基本数据类型)都有一个“静态”的 class 属性
      • 通过 Class 类的静态方法:forName(String className) ( 常用)
         package demo.reflect;
        

        public class ReflectTarget {
        public static void main(String[] args) throws ClassNotFoundException {
        // 第一种方式获取 Class 对象
        ReflectTarget reflectTarget = new ReflectTarget();
        Class reflectClass01 = reflectTarget.getClass();
        System.out.println("1st:" + reflectClass01);

             <span class="hljs-comment">//通过第二种方式获取Class对象</span>
             Class reflectClass02 = ReflectTarget.<span class="hljs-keyword">class</span>;
             System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"2nd: "</span> + reflectClass01);
        
             <span class="hljs-comment">//比较第一种方式获取得class对象和第二种方式获取得class对象是否为同一个</span>
             System.<span class="hljs-keyword">out</span>.println(reflectClass01 == reflectClass02);
        
             <span class="hljs-comment">// 第三种方式获取Class对象</span>
             Class reflectClass03 = Class.forName(<span class="hljs-string">"demo.reflect.ReflectTarget"</span>);
             System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"3rd: "</span> + reflectClass03);
        
             <span class="hljs-comment">//比较第二种方式获取得class对象和第三种方式获取得class对象是否为同一个</span>
             System.<span class="hljs-keyword">out</span>.println(reflectClass02 == reflectClass03);
         }
        

        }

        /运行结果如下/
        /*

        • 1st: class demo.reflect.ReflectTarget
        • 2nd: class demo.reflect.ReflectTarget
        • true
        • 3rd: class demo.reflect.ReflectTarget
        • true
        • /
          /
          *
        • 根据运行结果得知:Class 对象有且仅有一个
        • **/
        </code></pre>
        </li>
        <li>Class对象就像一面镜子,透过这面镜子可以看到类的结构</li>
        </ul>
        </li>
        </ul>
        </li>
        </ol>
        <h3 id="blogTitle5">反射的主要用法<button class="cnblogs-toc-button" title="显示目录导航"></button></h3>
        <ul>
        <li>如何获取类的构造方法并使用
        <ul>
        <li>在我们上面自定义的ReflectTarget类中创建各种类型的构造函数,用于测试<pre class="highlighter-hljs" highlighted="true"><code class="highlighter-hljs hljs language-csharp"> <span class="hljs-comment">// --------构造函数--------</span>
        <span class="hljs-comment">// 访问修饰符为默认的构造函数,即同包可访问得</span>
        ReflectTarget(String str) {
            System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"(默认)的构造方法 s= "</span> + str);
        }
        <span class="hljs-comment">//无参构造函数</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ReflectTarget</span>()</span> {
            System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"调用了公有的无参构造函数。。。"</span>);
        }
        <span class="hljs-comment">//有一个参数的构造函数</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ReflectTarget</span>(<span class="hljs-params"><span class="hljs-built_in">char</span> name</span>)</span> {
            System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"调用了带有一个参数构造函数,参数为:"</span> + name);
        }
        <span class="hljs-comment">//有多个参数的构造函数</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ReflectTarget</span>(<span class="hljs-params">String name,<span class="hljs-built_in">int</span> index</span>)</span> {
            System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"调用了有多个参数构造函数,参数值为【目标名】:"</span> + name + <span class="hljs-string">"【序号】"</span> + index);
        }
        <span class="hljs-comment">//受保护的构造函数</span>
        <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-title">ReflectTarget</span>(<span class="hljs-params">boolean b</span>)</span> {
            System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"受保护的构造方法:"</span> + b);
        }
        <span class="hljs-comment">//私有的构造函数</span>
        <span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-title">ReflectTarget</span>(<span class="hljs-params"><span class="hljs-built_in">int</span> index</span>)</span>{
            System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"私有的构造方法,序号:"</span> + index);
        }
        </code></pre>
        </li>
        <li>新创建一个类ConstructorCollector测试通过反射获取目标反射类的所有构造方法<pre class="highlighter-hljs" highlighted="true"><code class="highlighter-hljs hljs language-csharp">   package demo.reflect;
        
           import java.lang.reflect.Constructor;
           import java.lang.reflect.InvocationTargetException;
           
           <span class="hljs-comment">/**
            * 获取构造方法:
            *    1)批量构造方法
            *       public Constructor[] getConstructors() 获取所有”公有的“构造方法
            *       public Constructor[] getDeclaredConstructors() 获取所有的构造方法(包括私有的、受保护的、默认和公有的)
            *    2)获取单个的方法,并调用
            *       public Constructor getConstructor(Class...parameterTypes) 获取单个的”公有的“构造方法
            *       public Constructor getDeclaredConstructor(Class...parameterTypes) 获取某个构造方法(可以是私有的、受保护的、默认和公有的)
            *
            * 调用构造方法: Constructor --&gt; newInstance(Object...intArgs)
            */</span>
           <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ConstructorCollector</span> {
               <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span>(<span class="hljs-params">String[] args</span>) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException</span> {
                   Class clazz = Class.forName(<span class="hljs-string">"demo.reflect.ReflectTarget"</span>);
                   <span class="hljs-comment">// 获取所有的公有构造方法</span>
                   System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"**************所有公有的构造方法**************"</span>);
                   Constructor[] conArray = clazz.getConstructors();
                   <span class="hljs-keyword">for</span> (Constructor con : conArray) {
                       System.<span class="hljs-keyword">out</span>.println(con);
                   }
                   <span class="hljs-comment">// 获取所有的构造方法</span>
                   System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"**************所有的构造方法(包括私有的、受保护的、默认和公有的)**************"</span>);
                   conArray = clazz.getDeclaredConstructors();
                   <span class="hljs-keyword">for</span> (Constructor con : conArray) {
                       System.<span class="hljs-keyword">out</span>.println(con);
                   }
                   <span class="hljs-comment">//或获取单个带参数的公有构造方法</span>
                   System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"**************获取公有、带两个参数的构造方法**************"</span>);
                   Constructor con =  clazz.getConstructor(String.<span class="hljs-keyword">class</span>,<span class="hljs-built_in">int</span>.<span class="hljs-keyword">class</span>);
                   System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"con = "</span> + con);
                   <span class="hljs-comment">// 获取单个私有的构造方法</span>
                   System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"**************获取单个私有的构造方法**************"</span>);
                   con = clazz.getDeclaredConstructor(<span class="hljs-built_in">int</span>.<span class="hljs-keyword">class</span>);
                   System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"con = "</span> + con);
                   System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"##################################################"</span>);
                   System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"**************通过私有构造方法创建实例**************"</span>);
                   con.setAccessible(<span class="hljs-literal">true</span>); <span class="hljs-comment">// 设置暴力访问,忽略掉访问修饰符</span>
                   ReflectTarget reflectTarget = (ReflectTarget) con.newInstance(<span class="hljs-number">1</span>);
               }
           
           }
           
           <span class="hljs-comment">/***
            * 运行结果如下:
            * **************所有公有的构造方法**************
            * public demo.reflect.ReflectTarget(java.lang.String,int)
            * public demo.reflect.ReflectTarget()
            * public demo.reflect.ReflectTarget(char)
            * **************所有的构造方法(包括私有的、受保护的、默认和公有的)**************
            * private demo.reflect.ReflectTarget(int)
            * protected demo.reflect.ReflectTarget(boolean)
            * public demo.reflect.ReflectTarget(java.lang.String,int)
            * demo.reflect.ReflectTarget(java.lang.String)
            * public demo.reflect.ReflectTarget()
            * public demo.reflect.ReflectTarget(char)
            * **************获取公有、带两个参数的构造方法**************
            * con = public demo.reflect.ReflectTarget(java.lang.String,int)
            * **************获取单个私有的构造方法**************
            * con = private demo.reflect.ReflectTarget(int)
            * ##################################################
            * **************通过私有构造方法创建实例**************
            * 私有的构造方法,序号:1
            */</span>
        
        </code></pre>
        </li>
        </ul>
        </li>
        <li>如何获取类的字段并使用
        <ul>
        <li>在我们上面自定义的ReflectTarget类中创建各种不同访问修饰符修饰的字段,用于测试<pre class="highlighter-hljs" highlighted="true"><code class="highlighter-hljs hljs language-typescript"> <span class="hljs-comment">// --------字段--------</span>
        <span class="hljs-keyword">public</span> <span class="hljs-title class_">String</span> name;
        <span class="hljs-keyword">protected</span> int index;
        char <span class="hljs-keyword">type</span>;
        <span class="hljs-keyword">private</span> <span class="hljs-title class_">String</span> targetInfo;
        
        <span class="hljs-meta">@Override</span>
        <span class="hljs-keyword">public</span> <span class="hljs-title class_">String</span> <span class="hljs-title function_">toString</span>(<span class="hljs-params"></span>) {
            <span class="hljs-keyword">return</span> <span class="hljs-string">"ReflectTarget{"</span> +
                    <span class="hljs-string">"name='"</span> + name + <span class="hljs-string">'\''</span> +
                    <span class="hljs-string">", index="</span> + index +
                    <span class="hljs-string">", type="</span> + <span class="hljs-keyword">type</span> +
                    <span class="hljs-string">", targetInfo='"</span> + targetInfo+ <span class="hljs-string">'\''</span> +
                    <span class="hljs-string">'}'</span>;
        }
        </code></pre>
        </li>
        <li>新创建一个类FieldCollector 测试通过反射获取目标反射类的所有成员变量<pre class="highlighter-hljs" highlighted="true"><code class="highlighter-hljs hljs language-fsharp">    package demo.reflect;
        
        import java.lang.reflect.Field;
        import java.lang.reflect.InvocationTargetException;
        
        <span class="hljs-operator">/**</span>
         <span class="hljs-operator">*</span> 获取成员变量并调用:
         <span class="hljs-operator">*</span>    <span class="hljs-number">1</span>)批量的
         <span class="hljs-operator">*</span>       Field[] getFields() 获取所有的”公有字段”
         <span class="hljs-operator">*</span>       Field[] getDeclaredFields() 获取所有字段(包括私有的、受保护的、默认和公有的)
         <span class="hljs-operator">*</span>    <span class="hljs-number">2</span>)获取单个的
         <span class="hljs-operator">*</span>       <span class="hljs-keyword">public</span> Field getField(String fieldName) 获取单个的”公有的“字段
         <span class="hljs-operator">*</span>       <span class="hljs-keyword">public</span> Field getDeclaredField(String fieldName) 获取某个字段(可以是私有的、受保护的、默认和公有的)
         <span class="hljs-operator">*</span>
         <span class="hljs-operator">*</span>    设置字段值: Field <span class="hljs-operator">--&gt;</span> <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-built_in">set</span>(Object obj,Object value)
         <span class="hljs-operator">*</span>               参数说明:
         <span class="hljs-operator">*</span>               <span class="hljs-number">1.</span> obj:要设置的字段所对应的对象
         <span class="hljs-operator">*</span>               <span class="hljs-number">2.</span> value:要为字段设置的值
         <span class="hljs-operator">*/</span>
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> FieldCollector {
            <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
                <span class="hljs-comment">//获取class对象</span>
                Class reflectTargetClass <span class="hljs-operator">=</span> Class.forName(<span class="hljs-string">"demo.reflect.ReflectTarget"</span>);
                <span class="hljs-comment">//获取所有的公有字段</span>
                System.out.println(<span class="hljs-string">"**************获取所有的公有字段**************"</span>);
                Field[] fieldArray <span class="hljs-operator">=</span> reflectTargetClass.getFields();
                <span class="hljs-keyword">for</span> (Field field <span class="hljs-operator">:</span> fieldArray) {
                    System.out.println(field);
                }
                <span class="hljs-comment">//获取所有的字段</span>
                System.out.println(<span class="hljs-string">"**************获取所有字段(包括私有的、受保护的、默认和公有的)**************"</span>);
                fieldArray <span class="hljs-operator">=</span> reflectTargetClass.getDeclaredFields();
                <span class="hljs-keyword">for</span> (Field field <span class="hljs-operator">:</span> fieldArray) {
                    System.out.println(field);
                }
                <span class="hljs-comment">// 获取公有字段并赋值</span>
                System.out.println(<span class="hljs-string">"**************获取公有字段并赋值**************"</span>);
                Field field <span class="hljs-operator">=</span> reflectTargetClass.getField(<span class="hljs-string">"name"</span>);
                System.out.println(<span class="hljs-string">"公有的字段 name = "</span> <span class="hljs-operator">+</span> field);
                <span class="hljs-comment">// 通过反射调用无参构造方法,并使用无参构造创建对象</span>
                ReflectTarget reflectTarget <span class="hljs-operator">=</span> (ReflectTarget)reflectTargetClass.getConstructor().newInstance();
                <span class="hljs-comment">// 给获取对象的field属性赋值</span>
                field.<span class="hljs-built_in">set</span>(reflectTarget,<span class="hljs-string">"待反射一号"</span>);
                <span class="hljs-comment">// 验证对应的值 name</span>
                System.out.println(<span class="hljs-string">"验证name: "</span> <span class="hljs-operator">+</span> reflectTarget.name); <span class="hljs-comment">// 因为name属性是公有的,所以可以直接通过实例调用</span>
                System.out.println(<span class="hljs-string">"**************获取私有字段targetInfo并赋值**************"</span>);
                field <span class="hljs-operator">=</span> reflectTargetClass.getDeclaredField(<span class="hljs-string">"targetInfo"</span>);
                System.out.println(field);
                field.setAccessible(<span class="hljs-literal">true</span>); <span class="hljs-comment">// 设置暴力访问</span>
                field.<span class="hljs-built_in">set</span>(reflectTarget,<span class="hljs-string">"13730862985"</span>);
                <span class="hljs-comment">// 因为targetInfo属性是私有的,不能直接通过实例调用,由于我们重写了toString方法,所以直接打印reflectTarget对象就好了</span>
                System.out.println(<span class="hljs-string">"验证targetInfo: "</span> <span class="hljs-operator">+</span> reflectTarget);
        
            }
        }
        <span class="hljs-operator">/**</span>
         <span class="hljs-operator">*</span> 运行结果如下:
         <span class="hljs-operator">*</span> <span class="hljs-operator">**************</span>获取所有的公有字段<span class="hljs-operator">**************</span>
         <span class="hljs-operator">*</span> <span class="hljs-keyword">public</span> java.lang.String demo.reflect.ReflectTarget.name
         <span class="hljs-operator">*</span> <span class="hljs-operator">**************</span>获取所有字段(包括私有的、受保护的、默认和公有的)<span class="hljs-operator">**************</span>
         <span class="hljs-operator">*</span> <span class="hljs-keyword">public</span> java.lang.String demo.reflect.ReflectTarget.name
         <span class="hljs-operator">*</span> protected int demo.reflect.ReflectTarget.index
         <span class="hljs-operator">*</span> char demo.reflect.ReflectTarget.<span class="hljs-keyword">type</span>
         <span class="hljs-operator">*</span> <span class="hljs-keyword">private</span> java.lang.String demo.reflect.ReflectTarget.targetInfo
         <span class="hljs-operator">*</span> <span class="hljs-operator">**************</span>获取公有字段并赋值<span class="hljs-operator">**************</span>
         <span class="hljs-operator">*</span> 公有的字段 name <span class="hljs-operator">=</span> <span class="hljs-keyword">public</span> java.lang.String demo.reflect.ReflectTarget.name
         <span class="hljs-operator">*</span> 调用了公有的无参构造函数。。。
         <span class="hljs-operator">*</span> 验证name<span class="hljs-operator">:</span> 待反射一号
         <span class="hljs-operator">*</span> <span class="hljs-operator">**************</span>获取私有字段targetInfo并赋值<span class="hljs-operator">**************</span>
         <span class="hljs-operator">*</span> <span class="hljs-keyword">private</span> java.lang.String demo.reflect.ReflectTarget.targetInfo
         <span class="hljs-operator">*</span> 验证targetInfo<span class="hljs-operator">:</span> ReflectTarget{name<span class="hljs-operator">=</span>'待反射一号', index<span class="hljs-operator">=</span><span class="hljs-number">0</span>, <span class="hljs-keyword">type</span><span class="hljs-operator">=</span> , targetInfo<span class="hljs-operator">=</span>'<span class="hljs-number">13730862985</span>'}
         <span class="hljs-operator">*/</span>
        </code></pre>
        </li>
        <li>注意:通过getField()方法可以获取到从父类继承的公有字段,但getDeclareField()方法是获取不到从父类继承的字段的</li>
        </ul>
        </li>
        <li>如何获取类的方法并调用
        <ul>
        <li>在在我们上面自定义的ReflectTarget类中创建被各种不同访问修饰符修饰的方法,用于测试<pre class="highlighter-hljs" highlighted="true"><code class="highlighter-hljs hljs language-java">       <span class="hljs-keyword">package</span> demo.reflect;
           
           <span class="hljs-keyword">import</span> java.lang.reflect.InvocationTargetException;
           <span class="hljs-keyword">import</span> java.lang.reflect.Method;
           
           <span class="hljs-comment">/**
            * 获取成员方法并调用:
            *    1)批量的
            *       public Method[] getMethods() 获取所有的”公有方法”(包含了父类的方法,也包含了Object类中的公有方法)
            *       public Method[] getDeclaredMethods() 获取所有成员方法(包括私有的、受保护的、默认和公有的)
            *    2)获取单个的
            *       public Method getMethod(String name,Class&lt;?&gt;...parameterTypes) 获取单个的”公有的“字段
            *              参数:
            *                  name: 方法名
            *                  Class...: 形参的Class类型对象
            *       public Method getDeclaredMethod(String name,Class&lt;?&gt;...parameterTypes) 获取某个字段(可以是私有的、受保护的、默认和公有的)
            *
            *  调用方法:
            *    Method --&gt; public Object invoke(Object obj,Object...args);
            *          参数说明:
            *          obj: 待调用方法方法的对象
            *          args: 调用方法时所传递的实参
            */</span>
           <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">MethodCollector</span> {
               <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
                   <span class="hljs-comment">//获取class对象</span>
                   <span class="hljs-type">Class</span> <span class="hljs-variable">reflectTargetClass</span> <span class="hljs-operator">=</span> Class.forName(<span class="hljs-string">"demo.reflect.ReflectTarget"</span>);
                   <span class="hljs-comment">// 获取所有的公有方法</span>
                   System.out.println(<span class="hljs-string">"*******************获取所有的public方法,包括父类和Object*******************"</span>);
                   Method[] methodArray = reflectTargetClass.getMethods();
                   <span class="hljs-keyword">for</span> (Method method : methodArray) {
                       System.out.println(method);
                   }
                   <span class="hljs-comment">// 获取该类所有的方法</span>
                   System.out.println(<span class="hljs-string">"*******************获取该类所有的方法,包括私有的*******************"</span>);
                   methodArray = reflectTargetClass.getDeclaredMethods();
                   <span class="hljs-keyword">for</span> (Method method : methodArray) {
                       System.out.println(method);
                   }
                   <span class="hljs-comment">// 获取单个公有方法</span>
                   System.out.println(<span class="hljs-string">"*******************获取公有的show1()*******************"</span>);
                   <span class="hljs-type">Method</span> <span class="hljs-variable">method</span> <span class="hljs-operator">=</span> reflectTargetClass.getMethod(<span class="hljs-string">"show1"</span>, String.class);
                   System.out.println(method);
                   <span class="hljs-comment">// 通过反射调用无参构造方法,并使用无参构造创建对象</span>
                   <span class="hljs-type">ReflectTarget</span> <span class="hljs-variable">reflectTarget</span> <span class="hljs-operator">=</span> (ReflectTarget)reflectTargetClass.getConstructor().newInstance();
                   method.invoke(reflectTarget,<span class="hljs-string">"待反射方法一号"</span>);
                   System.out.println(<span class="hljs-string">"*******************获取私有的show4()*******************"</span>);
                   method = reflectTargetClass.getDeclaredMethod(<span class="hljs-string">"show4"</span>, <span class="hljs-type">int</span>.class);
                   System.out.println(method);
                   method.setAccessible(<span class="hljs-literal">true</span>);
                   <span class="hljs-comment">// 接受show4()的返回值</span>
                   <span class="hljs-type">String</span> <span class="hljs-variable">result</span> <span class="hljs-operator">=</span> String.valueOf(method.invoke(reflectTarget, <span class="hljs-number">100</span>)) ;
                   System.out.println(result);
               }
           }
           <span class="hljs-comment">/**
            * 运行结果如下:我们从运行结果可以看到通过getMethods(),获取到Object类中的公有方法
            * *******************获取所有的public方法,包括父类和Object*******************
            * public static void demo.reflect.ReflectTarget.main(java.lang.String[]) throws java.lang.ClassNotFoundException
            * public java.lang.String demo.reflect.ReflectTarget.toString()
            * public void demo.reflect.ReflectTarget.show1(java.lang.String)
            * public final void java.lang.Object.wait() throws java.lang.InterruptedException
            * public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
            * public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
            * public boolean java.lang.Object.equals(java.lang.Object)
            * public native int java.lang.Object.hashCode()
            * public final native java.lang.Class java.lang.Object.getClass()
            * public final native void java.lang.Object.notify()
            * public final native void java.lang.Object.notifyAll()
            * *******************获取该类所有的方法,包括私有的*******************
            * public static void demo.reflect.ReflectTarget.main(java.lang.String[]) throws java.lang.ClassNotFoundException
            * public java.lang.String demo.reflect.ReflectTarget.toString()
            * public void demo.reflect.ReflectTarget.show1(java.lang.String)
            * private java.lang.String demo.reflect.ReflectTarget.show4(int)
            * protected void demo.reflect.ReflectTarget.show2()
            * void demo.reflect.ReflectTarget.show3()
            * *******************获取公有的show1()*******************
            * public void demo.reflect.ReflectTarget.show1(java.lang.String)
            * 调用了公有的无参构造函数。。。
            * 调用了公有的,String参数的show1(): str = 待反射方法一号
            * *******************获取私有的show4()*******************
            * private java.lang.String demo.reflect.ReflectTarget.show4(int)
            * 调用了私有的,并且有返回值的,int参数的show4(): index = 100
            * show4Result
            */</span>
           
        </code></pre>
        </li>
        </ul>
        </li>
        </ul>
        <h2 id="blogTitle6">注解<button class="cnblogs-toc-button" title="显示目录导航"></button></h2>
        <h3 id="blogTitle7">注解介绍及作用<button class="cnblogs-toc-button" title="显示目录导航"></button></h3>
        <p>  由于反射需要获取到相关的类全名(类名+包名),因此我们还需要记录哪些类是通过反射来获取的。我们可以通过XML来保存类相关的信息已供反射用,此外,我们还可以通过注解来保存类相关信息以供反射调用。<br>
          注解:提供一种为程序元素设置元数据的方法</p>
        <ul>
        <li>元数据是添加到程序元素如方法、字段、类和包上的额外信息</li>
        <li>注解是一种分散式的元数据设置方式,XML是集中式的设置方式</li>
        <li>注解不能直接干扰程序运行</li>
        <li>反编译字节码文件的指令:javap -verbose com.reminis.demo.annotation.TestAnnotation,通过反编译可以看到我们的自定义注解自动继承了Annotation</li>
        <li>注解的功能
        <ul>
        <li>作为特定得标记,用于告诉编译器一些信息</li>
        <li>编译时动态处理,如动态生成代码</li>
        <li>运行时动态处理,作为额外信息的载体,如获取注解信息</li>
        </ul>
        </li>
        <li>注解的分类
        <ul>
        <li>标准注解:Override、Deprecated、SuppressWarnings</li>
        <li>元注解:@Retention、@Target、@Inherited、@Documented,用于修饰注解的注解,通常用在注解的定义上
        <ul>
        <li>@Target:注解的作用目标,描述所修饰注解的使用范围
        <ul>
        <li>packages、types(类、接口、枚举、Annotation类型)</li>
        <li>类型成员(方法、构造方法、成员变量、枚举值)</li>
        <li>方法参数和本地变量(如循环变量、catch参数)</li>
        </ul>
        </li>
        <li>@Retention:注解的生命周期(标注注解保留时间的长短)</li>
        <li>@Documented:注解是否应当被包含在JavaDoc文档中</li>
        <li>@Inherited:是否允许子类继承该注解</li>
        </ul>
        </li>
        </ul>
        </li>
        </ul>
        <h3 id="blogTitle8">自定义注解的实现<button class="cnblogs-toc-button" title="显示目录导航"></button></h3>
        <p>  自定义注解自动实现了 java.lang.annotation.Annotation</p>
        <pre class="highlighter-hljs" highlighted="true"><code class="highlighter-hljs hljs language-scss"> public <span class="hljs-keyword">@interface</span> 注解名{
           修饰符 返回值 属性名() 默认值;
           修饰符 返回值 属性名() 默认值;
           ...
        }
        </code></pre>
        <p>  注解属性支持的类型:所有的基本类型(int,float,boolean,byte,double,char,long,short)、 String 类型、 Class类型、Enum类型、Annotation类型、以上所有类型的数组。<br>
          我们现在自定义一个注解PersonInfoAnnotation,可以用在字段上,在程序运行时有效,如下:</p>
        <pre class="highlighter-hljs" highlighted="true"><code class="highlighter-hljs hljs language-java"><span class="hljs-keyword">package</span> demo.annotation;
        
        <span class="hljs-keyword">import</span> java.lang.annotation.ElementType;
        <span class="hljs-keyword">import</span> java.lang.annotation.Retention;
        <span class="hljs-keyword">import</span> java.lang.annotation.RetentionPolicy;
        <span class="hljs-keyword">import</span> java.lang.annotation.Target;
        
        <span class="hljs-comment">/**
        * 自定义注解
        */</span>
        <span class="hljs-meta">@Target(ElementType.FIELD)</span>
        <span class="hljs-meta">@Retention(RetentionPolicy.RUNTIME)</span>
        <span class="hljs-keyword">public</span> <span class="hljs-meta">@interface</span> PersonInfoAnnotation {
           <span class="hljs-comment">//名字</span>
           <span class="hljs-keyword">public</span> String <span class="hljs-title function_">name</span><span class="hljs-params">()</span>;
           <span class="hljs-comment">// 年龄</span>
           <span class="hljs-keyword">public</span> <span class="hljs-type">int</span> <span class="hljs-title function_">age</span><span class="hljs-params">()</span> <span class="hljs-keyword">default</span> <span class="hljs-number">19</span>;
           <span class="hljs-comment">// 性别</span>
           <span class="hljs-keyword">public</span> String <span class="hljs-title function_">gender</span><span class="hljs-params">()</span> <span class="hljs-keyword">default</span> <span class="hljs-string">"男"</span>;
           <span class="hljs-comment">// 开发语言</span>
           <span class="hljs-keyword">public</span> String[] language();
        }
        </code></pre>
        <p>  我们再自定义一个注解CourseInfoAnnotation,该注解可以用在类和方法上,在程序运行时有效,如下:</p>
        <pre class="highlighter-hljs" highlighted="true"><code class="highlighter-hljs hljs language-java"><span class="hljs-keyword">package</span> demo.annotation;
        
        <span class="hljs-keyword">import</span> java.lang.annotation.ElementType;
        <span class="hljs-keyword">import</span> java.lang.annotation.Retention;
        <span class="hljs-keyword">import</span> java.lang.annotation.RetentionPolicy;
        <span class="hljs-keyword">import</span> java.lang.annotation.Target;
        
        <span class="hljs-meta">@Target({ElementType.TYPE,ElementType.METHOD})</span>
        <span class="hljs-meta">@Retention(RetentionPolicy.RUNTIME)</span>
        <span class="hljs-keyword">public</span> <span class="hljs-meta">@interface</span> CourseInfoAnnotation {
           <span class="hljs-comment">// 课程名称</span>
           <span class="hljs-keyword">public</span> String <span class="hljs-title function_">courseName</span><span class="hljs-params">()</span>;
           <span class="hljs-comment">// 课程 标签</span>
           <span class="hljs-keyword">public</span> String <span class="hljs-title function_">courseTag</span><span class="hljs-params">()</span>;
           <span class="hljs-comment">// 课程简介</span>
           <span class="hljs-keyword">public</span> String <span class="hljs-title function_">courseProfile</span><span class="hljs-params">()</span>;
           <span class="hljs-comment">// 课程代号</span>
           <span class="hljs-keyword">public</span> <span class="hljs-type">int</span> <span class="hljs-title function_">courseIndex</span><span class="hljs-params">()</span> <span class="hljs-keyword">default</span> <span class="hljs-number">107</span>;
        }
        </code></pre>
        <p>  新创建一个SelfStudyCourse类,在该类上及该类的字段和方法上,使用我们上面的已经定义好了的注解</p>
        <pre class="highlighter-hljs" highlighted="true"><code class="highlighter-hljs hljs language-kotlin"><span class="hljs-keyword">package</span> demo.<span class="hljs-keyword">annotation</span>;
        
        <span class="hljs-meta">@CourseInfoAnnotation(courseName = <span class="hljs-string">"计算机网络"</span>,courseTag = <span class="hljs-string">"计算机基础"</span>,
               courseProfile = <span class="hljs-string">"计算机网络学习的核心内容就是网络协议的学习。"</span> +
                       <span class="hljs-string">"网络协议是为计算机网络中进行数据交换而建立的规则、标准或者说是约定的集合。"</span> +
                       <span class="hljs-string">"因为不同用户的数据终端可能采取的字符集是不同的,两者需要进行通信,必须要在一定的标准上进行"</span>)</span>
        <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SelfStudyCourse</span> </span>{
           <span class="hljs-meta">@PersonInfoAnnotation(name = <span class="hljs-string">"新一"</span>,language = {<span class="hljs-string">"Java"</span>,<span class="hljs-string">"C++"</span>,<span class="hljs-string">"Go"</span>,<span class="hljs-string">"Python"</span>})</span>
           <span class="hljs-keyword">public</span> String author;
        
        
           <span class="hljs-meta">@CourseInfoAnnotation(courseName = <span class="hljs-string">"Linux 教程"</span>,courseTag = <span class="hljs-string">"编程基础"</span>,
           courseProfile = <span class="hljs-string">"Linux 遵循 GNU 通用公共许可证(GPL),任何个人和机构都可以自由地使用 Linux 的所有底层源代码,也可以自由地修改和再发布。"</span> +
                   <span class="hljs-string">"由于 Linux 是自由软件,任何人都可以创建一个符合自己需求的 Linux 发行版"</span>,courseIndex = 208)</span>
           <span class="hljs-keyword">public</span> void getCourseInfo(){
        
           }
        
        }
        
        </code></pre>
        <p>  创建测试类AnnotationDemo,调用上面使用了自定义注解的类的方法,查看运行信息</p>
        <pre class="highlighter-hljs" highlighted="true"><code class="highlighter-hljs hljs language-csharp">package demo.annotation;
        
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">AnnotationDemo</span> {
           <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span>(<span class="hljs-params">String[] args</span>)</span> {
               SelfStudyCourse selfStudyCourse = <span class="hljs-keyword">new</span> SelfStudyCourse();
               selfStudyCourse.getCourseInfo();
               System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"finish"</span>);
           }
        }
        
        <span class="hljs-comment">/**
        * 运行结果:
        * finish
        * 根据运行结果可以看出,在程序中如果不对注解进行处理,和不加注解输出的信息是一致的,
        * */</span>
        </code></pre>
        <p>  如果我们不对注解进行处理,那和不加是没有区别的,那我们如何获取注解上得信息呢?通过前面说到得反射,我们查看反射涉及到得几个主要类(Field,Method,Constructor,Class)得源码可以知道,这些跟反射相关得类都实现了AnnotatedElement接口,我们通过查看AnnotatedElement接口的源码,常用的有如下几个方法:</p>
        <ul>
        <li>Annotation[] getAnnotations(); // 用来获取对象上的所有注解,包括继承过来的</li>
        <li><t extends="" annotation=""> T getAnnotation(Class<t> annotationClass); // 获取对象上单个指定的注解</t></t></li>
        <li>boolean isAnnotationPresent(Class&lt;? extends Annotation&gt; annotationClass); //用来判断是否有某个指定的注解</li>
        </ul>
        <p>   现在我们通过反射来获取类注解上的信息,代码实现如下:</p>
        <pre class="highlighter-hljs" highlighted="true"><code class="highlighter-hljs hljs language-java"><span class="hljs-keyword">package</span> demo.annotation;
        
        <span class="hljs-keyword">import</span> java.lang.annotation.Annotation;
        
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">AnnotationParse</span> {
        
           <span class="hljs-comment">//解析类上面的注解</span>
           <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">parseTypeAnnotation</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> ClassNotFoundException {
               Class&lt;?&gt; clazz = Class.forName(<span class="hljs-string">"demo.annotation.SelfStudyCourse"</span>);
               <span class="hljs-comment">// 这里获取的是class对象的注解,而不是其里面的方法和成员变量的注解</span>
               Annotation[] annotations = clazz.getAnnotations();
               <span class="hljs-keyword">for</span> (Annotation annotation : annotations) {
                   <span class="hljs-type">CourseInfoAnnotation</span> <span class="hljs-variable">courseInfoAnnotation</span> <span class="hljs-operator">=</span> (CourseInfoAnnotation) annotation;
                   System.out.println(<span class="hljs-string">"课程名: "</span> +courseInfoAnnotation.courseName() + <span class="hljs-string">"\n"</span> +
                           <span class="hljs-string">"课程标签: "</span> + courseInfoAnnotation.courseTag() + <span class="hljs-string">"\n"</span> +
                           <span class="hljs-string">"课程简介: "</span>+ courseInfoAnnotation.courseProfile() + <span class="hljs-string">"\n"</span> +
                           <span class="hljs-string">"课程代号: "</span> + courseInfoAnnotation.courseIndex());
               }
           }
        
           <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">main</span><span class="hljs-params">(String[] args)</span> <span class="hljs-keyword">throws</span> ClassNotFoundException {
               parseTypeAnnotation();
           }
        }
        
        <span class="hljs-comment">/**
        * 程序运行结果如下:
        * 课程名: 计算机网络
        * 课程标签: 计算机基础
        * 课程简介: 计算机网络学习的核心内容就是网络协议的学习。网络协议是为计算机网络中进行数据交换而建立的规则、标准或者说是约定的集合。因为不同用户的数据终端可能采取的字符集是不同的,两者需要进行通信,必须要在一定的标准上进行
        * 课程代号: 107
        */</span>
        </code></pre>
        <p>  现在通过来反射来获取成员变量和方法上的注解信息</p>
        <pre class="highlighter-hljs" highlighted="true"><code class="highlighter-hljs hljs language-csharp">    <span class="hljs-comment">// 解析字段上的注解信息</span>
           <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">parseFieldAnnotation</span>() throws ClassNotFoundException</span> {
               Class&lt;?&gt; clazz = Class.forName(<span class="hljs-string">"demo.annotation.SelfStudyCourse"</span>);
               <span class="hljs-comment">// 获取该对象的所有成员变量</span>
               Field[] fields = clazz.getDeclaredFields();
               <span class="hljs-keyword">for</span> (Field field : fields) {
                   <span class="hljs-comment">// 判断成员变量中是否有指定注解类型的注解</span>
                   boolean hasAnnotation = field.isAnnotationPresent(PersonInfoAnnotation.<span class="hljs-keyword">class</span>);
                   <span class="hljs-keyword">if</span> (hasAnnotation) {
                       PersonInfoAnnotation personInfoAnnotation = field.getAnnotation(PersonInfoAnnotation.<span class="hljs-keyword">class</span>);
                       System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"名字: "</span> + personInfoAnnotation.name() + <span class="hljs-string">"\n"</span> +
                               <span class="hljs-string">"年龄: "</span> + personInfoAnnotation.age() + <span class="hljs-string">"\n"</span> +
                               <span class="hljs-string">"性别: "</span> + personInfoAnnotation.gender());
                       <span class="hljs-keyword">for</span> (String language : personInfoAnnotation.language()) {
                           System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"课程名: "</span> + language);
                       }
                   }
               }
           }
        
           <span class="hljs-comment">// 解析方法上的注解信息</span>
           <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">parseMethodAnnotation</span>() throws ClassNotFoundException</span> {
               Class&lt;?&gt; clazz = Class.forName(<span class="hljs-string">"demo.annotation.SelfStudyCourse"</span>);
               <span class="hljs-comment">// 获取该对象的所有成员变量</span>
               Method[] methods = clazz.getMethods();
               <span class="hljs-keyword">for</span> (Method method : methods) {
                   <span class="hljs-comment">// 判断方法中是否有指定注解类型的注解</span>
                   boolean hasAnnotation = method.isAnnotationPresent(CourseInfoAnnotation.<span class="hljs-keyword">class</span>);
                   <span class="hljs-keyword">if</span> (hasAnnotation) {
                       CourseInfoAnnotation methodAnnotation = method.getAnnotation(CourseInfoAnnotation.<span class="hljs-keyword">class</span>);
                       System.<span class="hljs-keyword">out</span>.println(<span class="hljs-string">"课程名: "</span> +methodAnnotation.courseName() + <span class="hljs-string">"\n"</span> +
                               <span class="hljs-string">"课程标签: "</span> + methodAnnotation.courseTag() + <span class="hljs-string">"\n"</span> +
                               <span class="hljs-string">"课程简介: "</span>+ methodAnnotation.courseProfile() + <span class="hljs-string">"\n"</span> +
                               <span class="hljs-string">"课程代号: "</span> + methodAnnotation.courseIndex());
                   }
               }
           }
        </code></pre>
        <p>  注解获取属性值的底层实现,是通过JVM为注解生成代理对象。</p>
        <h3 id="blogTitle9">注解的工作原理<button class="cnblogs-toc-button" title="显示目录导航"></button></h3>
        <ul>
        <li>通过键值对的形式为注解属性赋值</li>
        <li>编译器检查注解的使用范围,将注解信息写入元素属性表,</li>
        <li>运行时JVM将RUNTIME的所有注解属性取出并最终存入map里</li>
        <li>创建AnnotationInvocationHandler实例并传入前面的map中</li>
        <li>JVM使用JDK动态代理为注解生成代理类,并初始化对应的处理器(AnnotationInvocationHandler)</li>
        <li>调用invoke方法,通过传入方法名返回注解对应的属性值</li>
        </ul>