泛型

泛型概念

  泛型是在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 {
      
          //给泛型加如上边界 ? extends E, 泛型类型必须是E的类型或其子类
      public static void handleMember(GenericClassExample<? extends Number> integerExample) {
      Integer result = (Integer) integerExample.getMember() + 100;
      System.out.println("result is " + result);
      } //给泛型加入下边界 ? super E ,泛型类型必须是E的类型或其父类
      public static void handleSuperMember(GenericClassExample<? super Integer> integerExample) {
      Integer result = (Integer) integerExample.getMember() + 100;
      System.out.println("result is " + result);
      } public static void main(String[] args) {
      GenericClassExample<String> strExample = new GenericClassExample<>("abc");
      GenericClassExample<Integer> integerExample = new GenericClassExample<>(123);
      GenericClassExample<Number> numberExample = new GenericClassExample<>(new Integer(123));
      // 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); //通过第二种方式获取Class对象
        Class reflectClass02 = ReflectTarget.class;
        System.out.println("2nd: " + reflectClass01); //比较第一种方式获取得class对象和第二种方式获取得class对象是否为同一个
        System.out.println(reflectClass01 == reflectClass02); // 第三种方式获取Class对象
        Class reflectClass03 = Class.forName("demo.reflect.ReflectTarget");
        System.out.println("3rd: " + reflectClass03); //比较第二种方式获取得class对象和第三种方式获取得class对象是否为同一个
        System.out.println(reflectClass02 == reflectClass03);
        }
        } /************运行结果如下************/
        /*
        * 1st: class demo.reflect.ReflectTarget
        * 2nd: class demo.reflect.ReflectTarget
        * true
        * 3rd: class demo.reflect.ReflectTarget
        * true
        * */
        /**
        * 根据运行结果得知:Class对象有且仅有一个
        * **/
        ```
      • Class对象就像一面镜子,透过这面镜子可以看到类的结构

反射的主要用法

  • 如何获取类的构造方法并使用

    • 在我们上面自定义的ReflectTarget类中创建各种类型的构造函数,用于测试
       // --------构造函数--------
      // 访问修饰符为默认的构造函数,即同包可访问得
      ReflectTarget(String str) {
      System.out.println("(默认)的构造方法 s= " + str);
      }
      //无参构造函数
      public ReflectTarget() {
      System.out.println("调用了公有的无参构造函数。。。");
      }
      //有一个参数的构造函数
      public ReflectTarget(char name) {
      System.out.println("调用了带有一个参数构造函数,参数为:" + name);
      }
      //有多个参数的构造函数
      public ReflectTarget(String name,int index) {
      System.out.println("调用了有多个参数构造函数,参数值为【目标名】:" + name + "【序号】" + index);
      }
      //受保护的构造函数
      protected ReflectTarget(boolean b) {
      System.out.println("受保护的构造方法:" + b);
      }
      //私有的构造函数
      private ReflectTarget(int index){
      System.out.println("私有的构造方法,序号:" + index);
      }
    • 新创建一个类ConstructorCollector测试通过反射获取目标反射类的所有构造方法
         package demo.reflect;
      
          import java.lang.reflect.Constructor;
      import java.lang.reflect.InvocationTargetException; /**
      * 获取构造方法:
      * 1)批量构造方法
      * public Constructor[] getConstructors() 获取所有”公有的“构造方法
      * public Constructor[] getDeclaredConstructors() 获取所有的构造方法(包括私有的、受保护的、默认和公有的)
      * 2)获取单个的方法,并调用
      * public Constructor getConstructor(Class...parameterTypes) 获取单个的”公有的“构造方法
      * public Constructor getDeclaredConstructor(Class...parameterTypes) 获取某个构造方法(可以是私有的、受保护的、默认和公有的)
      *
      * 调用构造方法: Constructor --> newInstance(Object...intArgs)
      */
      public class ConstructorCollector {
      public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
      Class clazz = Class.forName("demo.reflect.ReflectTarget");
      // 获取所有的公有构造方法
      System.out.println("**************所有公有的构造方法**************");
      Constructor[] conArray = clazz.getConstructors();
      for (Constructor con : conArray) {
      System.out.println(con);
      }
      // 获取所有的构造方法
      System.out.println("**************所有的构造方法(包括私有的、受保护的、默认和公有的)**************");
      conArray = clazz.getDeclaredConstructors();
      for (Constructor con : conArray) {
      System.out.println(con);
      }
      //或获取单个带参数的公有构造方法
      System.out.println("**************获取公有、带两个参数的构造方法**************");
      Constructor con = clazz.getConstructor(String.class,int.class);
      System.out.println("con = " + con);
      // 获取单个私有的构造方法
      System.out.println("**************获取单个私有的构造方法**************");
      con = clazz.getDeclaredConstructor(int.class);
      System.out.println("con = " + con);
      System.out.println("##################################################");
      System.out.println("**************通过私有构造方法创建实例**************");
      con.setAccessible(true); // 设置暴力访问,忽略掉访问修饰符
      ReflectTarget reflectTarget = (ReflectTarget) con.newInstance(1);
      } } /***
      * 运行结果如下:
      * **************所有公有的构造方法**************
      * 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
      */
  • 如何获取类的字段并使用
    • 在我们上面自定义的ReflectTarget类中创建各种不同访问修饰符修饰的字段,用于测试
       // --------字段--------
      public String name;
      protected int index;
      char type;
      private String targetInfo; @Override
      public String toString() {
      return "ReflectTarget{" +
      "name='" + name + '\'' +
      ", index=" + index +
      ", type=" + type +
      ", targetInfo='" + targetInfo+ '\'' +
      '}';
      }
    • 新创建一个类FieldCollector 测试通过反射获取目标反射类的所有成员变量
          package demo.reflect;
      
       import java.lang.reflect.Field;
      import java.lang.reflect.InvocationTargetException; /**
      * 获取成员变量并调用:
      * 1)批量的
      * Field[] getFields() 获取所有的”公有字段”
      * Field[] getDeclaredFields() 获取所有字段(包括私有的、受保护的、默认和公有的)
      * 2)获取单个的
      * public Field getField(String fieldName) 获取单个的”公有的“字段
      * public Field getDeclaredField(String fieldName) 获取某个字段(可以是私有的、受保护的、默认和公有的)
      *
      * 设置字段值: Field --> public void set(Object obj,Object value)
      * 参数说明:
      * 1. obj:要设置的字段所对应的对象
      * 2. value:要为字段设置的值
      */
      public class FieldCollector {
      public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
      //获取class对象
      Class reflectTargetClass = Class.forName("demo.reflect.ReflectTarget");
      //获取所有的公有字段
      System.out.println("**************获取所有的公有字段**************");
      Field[] fieldArray = reflectTargetClass.getFields();
      for (Field field : fieldArray) {
      System.out.println(field);
      }
      //获取所有的字段
      System.out.println("**************获取所有字段(包括私有的、受保护的、默认和公有的)**************");
      fieldArray = reflectTargetClass.getDeclaredFields();
      for (Field field : fieldArray) {
      System.out.println(field);
      }
      // 获取公有字段并赋值
      System.out.println("**************获取公有字段并赋值**************");
      Field field = reflectTargetClass.getField("name");
      System.out.println("公有的字段 name = " + field);
      // 通过反射调用无参构造方法,并使用无参构造创建对象
      ReflectTarget reflectTarget = (ReflectTarget)reflectTargetClass.getConstructor().newInstance();
      // 给获取对象的field属性赋值
      field.set(reflectTarget,"待反射一号");
      // 验证对应的值 name
      System.out.println("验证name: " + reflectTarget.name); // 因为name属性是公有的,所以可以直接通过实例调用
      System.out.println("**************获取私有字段targetInfo并赋值**************");
      field = reflectTargetClass.getDeclaredField("targetInfo");
      System.out.println(field);
      field.setAccessible(true); // 设置暴力访问
      field.set(reflectTarget,"13730862985");
      // 因为targetInfo属性是私有的,不能直接通过实例调用,由于我们重写了toString方法,所以直接打印reflectTarget对象就好了
      System.out.println("验证targetInfo: " + reflectTarget); }
      }
      /**
      * 运行结果如下:
      * **************获取所有的公有字段**************
      * public java.lang.String demo.reflect.ReflectTarget.name
      * **************获取所有字段(包括私有的、受保护的、默认和公有的)**************
      * public java.lang.String demo.reflect.ReflectTarget.name
      * protected int demo.reflect.ReflectTarget.index
      * char demo.reflect.ReflectTarget.type
      * private java.lang.String demo.reflect.ReflectTarget.targetInfo
      * **************获取公有字段并赋值**************
      * 公有的字段 name = public java.lang.String demo.reflect.ReflectTarget.name
      * 调用了公有的无参构造函数。。。
      * 验证name: 待反射一号
      * **************获取私有字段targetInfo并赋值**************
      * private java.lang.String demo.reflect.ReflectTarget.targetInfo
      * 验证targetInfo: ReflectTarget{name='待反射一号', index=0, type= , targetInfo='13730862985'}
      */
    • 注意:通过getField()方法可以获取到从父类继承的公有字段,但getDeclareField()方法是获取不到从父类继承的字段的
  • 如何获取类的方法并调用
    • 在在我们上面自定义的ReflectTarget类中创建被各种不同访问修饰符修饰的方法,用于测试
             package demo.reflect;
      
          import java.lang.reflect.InvocationTargetException;
      import java.lang.reflect.Method; /**
      * 获取成员方法并调用:
      * 1)批量的
      * public Method[] getMethods() 获取所有的”公有方法”(包含了父类的方法,也包含了Object类中的公有方法)
      * public Method[] getDeclaredMethods() 获取所有成员方法(包括私有的、受保护的、默认和公有的)
      * 2)获取单个的
      * public Method getMethod(String name,Class<?>...parameterTypes) 获取单个的”公有的“字段
      * 参数:
      * name: 方法名
      * Class...: 形参的Class类型对象
      * public Method getDeclaredMethod(String name,Class<?>...parameterTypes) 获取某个字段(可以是私有的、受保护的、默认和公有的)
      *
      * 调用方法:
      * Method --> public Object invoke(Object obj,Object...args);
      * 参数说明:
      * obj: 待调用方法方法的对象
      * args: 调用方法时所传递的实参
      */
      public class MethodCollector {
      public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
      //获取class对象
      Class reflectTargetClass = Class.forName("demo.reflect.ReflectTarget");
      // 获取所有的公有方法
      System.out.println("*******************获取所有的public方法,包括父类和Object*******************");
      Method[] methodArray = reflectTargetClass.getMethods();
      for (Method method : methodArray) {
      System.out.println(method);
      }
      // 获取该类所有的方法
      System.out.println("*******************获取该类所有的方法,包括私有的*******************");
      methodArray = reflectTargetClass.getDeclaredMethods();
      for (Method method : methodArray) {
      System.out.println(method);
      }
      // 获取单个公有方法
      System.out.println("*******************获取公有的show1()*******************");
      Method method = reflectTargetClass.getMethod("show1", String.class);
      System.out.println(method);
      // 通过反射调用无参构造方法,并使用无参构造创建对象
      ReflectTarget reflectTarget = (ReflectTarget)reflectTargetClass.getConstructor().newInstance();
      method.invoke(reflectTarget,"待反射方法一号");
      System.out.println("*******************获取私有的show4()*******************");
      method = reflectTargetClass.getDeclaredMethod("show4", int.class);
      System.out.println(method);
      method.setAccessible(true);
      // 接受show4()的返回值
      String result = String.valueOf(method.invoke(reflectTarget, 100)) ;
      System.out.println(result);
      }
      }
      /**
      * 运行结果如下:我们从运行结果可以看到通过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
      */

注解

注解介绍及作用

  由于反射需要获取到相关的类全名(类名+包名),因此我们还需要记录哪些类是通过反射来获取的。我们可以通过XML来保存类相关的信息已供反射用,此外,我们还可以通过注解来保存类相关信息以供反射调用。

  注解:提供一种为程序元素设置元数据的方法

  • 元数据是添加到程序元素如方法、字段、类和包上的额外信息
  • 注解是一种分散式的元数据设置方式,XML是集中式的设置方式
  • 注解不能直接干扰程序运行
  • 反编译字节码文件的指令:javap -verbose com.reminis.demo.annotation.TestAnnotation,通过反编译可以看到我们的自定义注解自动继承了Annotation
  • 注解的功能
    • 作为特定得标记,用于告诉编译器一些信息
    • 编译时动态处理,如动态生成代码
    • 运行时动态处理,作为额外信息的载体,如获取注解信息
  • 注解的分类
    • 标准注解:Override、Deprecated、SuppressWarnings
    • 元注解:@Retention、@Target、@Inherited、@Documented,用于修饰注解的注解,通常用在注解的定义上
      • @Target:注解的作用目标,描述所修饰注解的使用范围

        • packages、types(类、接口、枚举、Annotation类型)
        • 类型成员(方法、构造方法、成员变量、枚举值)
        • 方法参数和本地变量(如循环变量、catch参数)
      • @Retention:注解的生命周期(标注注解保留时间的长短)
      • @Documented:注解是否应当被包含在JavaDoc文档中
      • @Inherited:是否允许子类继承该注解

自定义注解的实现

  自定义注解自动实现了 java.lang.annotation.Annotation

 public @interface 注解名{
修饰符 返回值 属性名() 默认值;
修饰符 返回值 属性名() 默认值;
...
}

  注解属性支持的类型:所有的基本类型(int,float,boolean,byte,double,char,long,short)、 String 类型、 Class类型、Enum类型、Annotation类型、以上所有类型的数组。

  我们现在自定义一个注解PersonInfoAnnotation,可以用在字段上,在程序运行时有效,如下:

package demo.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* 自定义注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PersonInfoAnnotation {
//名字
public String name();
// 年龄
public int age() default 19;
// 性别
public String gender() default "男";
// 开发语言
public String[] language();
}

  我们再自定义一个注解CourseInfoAnnotation,该注解可以用在类和方法上,在程序运行时有效,如下:

package demo.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CourseInfoAnnotation {
// 课程名称
public String courseName();
// 课程 标签
public String courseTag();
// 课程简介
public String courseProfile();
// 课程代号
public int courseIndex() default 107;
}

  新创建一个SelfStudyCourse类,在该类上及该类的字段和方法上,使用我们上面的已经定义好了的注解

package demo.annotation;

@CourseInfoAnnotation(courseName = "计算机网络",courseTag = "计算机基础",
courseProfile = "计算机网络学习的核心内容就是网络协议的学习。" +
"网络协议是为计算机网络中进行数据交换而建立的规则、标准或者说是约定的集合。" +
"因为不同用户的数据终端可能采取的字符集是不同的,两者需要进行通信,必须要在一定的标准上进行")
public class SelfStudyCourse {
@PersonInfoAnnotation(name = "新一",language = {"Java","C++","Go","Python"})
public String author; @CourseInfoAnnotation(courseName = "Linux 教程",courseTag = "编程基础",
courseProfile = "Linux 遵循 GNU 通用公共许可证(GPL),任何个人和机构都可以自由地使用 Linux 的所有底层源代码,也可以自由地修改和再发布。" +
"由于 Linux 是自由软件,任何人都可以创建一个符合自己需求的 Linux 发行版",courseIndex = 208)
public void getCourseInfo(){ } }

  创建测试类AnnotationDemo,调用上面使用了自定义注解的类的方法,查看运行信息

package demo.annotation;

public class AnnotationDemo {
public static void main(String[] args) {
SelfStudyCourse selfStudyCourse = new SelfStudyCourse();
selfStudyCourse.getCourseInfo();
System.out.println("finish");
}
} /**
* 运行结果:
* finish
* 根据运行结果可以看出,在程序中如果不对注解进行处理,和不加注解输出的信息是一致的,
* */

  如果我们不对注解进行处理,那和不加是没有区别的,那我们如何获取注解上得信息呢?通过前面说到得反射,我们查看反射涉及到得几个主要类(Field,Method,Constructor,Class)得源码可以知道,这些跟反射相关得类都实现了AnnotatedElement接口,我们通过查看AnnotatedElement接口的源码,常用的有如下几个方法:

  • Annotation[] getAnnotations(); // 用来获取对象上的所有注解,包括继承过来的
  • T getAnnotation(Class annotationClass); // 获取对象上单个指定的注解
  • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass); //用来判断是否有某个指定的注解

   现在我们通过反射来获取类注解上的信息,代码实现如下:

package demo.annotation;

import java.lang.annotation.Annotation;

public class AnnotationParse {

    //解析类上面的注解
public static void parseTypeAnnotation() throws ClassNotFoundException {
Class<?> clazz = Class.forName("demo.annotation.SelfStudyCourse");
// 这里获取的是class对象的注解,而不是其里面的方法和成员变量的注解
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
CourseInfoAnnotation courseInfoAnnotation = (CourseInfoAnnotation) annotation;
System.out.println("课程名: " +courseInfoAnnotation.courseName() + "\n" +
"课程标签: " + courseInfoAnnotation.courseTag() + "\n" +
"课程简介: "+ courseInfoAnnotation.courseProfile() + "\n" +
"课程代号: " + courseInfoAnnotation.courseIndex());
}
} public static void main(String[] args) throws ClassNotFoundException {
parseTypeAnnotation();
}
} /**
* 程序运行结果如下:
* 课程名: 计算机网络
* 课程标签: 计算机基础
* 课程简介: 计算机网络学习的核心内容就是网络协议的学习。网络协议是为计算机网络中进行数据交换而建立的规则、标准或者说是约定的集合。因为不同用户的数据终端可能采取的字符集是不同的,两者需要进行通信,必须要在一定的标准上进行
* 课程代号: 107
*/

  现在通过来反射来获取成员变量和方法上的注解信息

    // 解析字段上的注解信息
public static void parseFieldAnnotation() throws ClassNotFoundException {
Class<?> clazz = Class.forName("demo.annotation.SelfStudyCourse");
// 获取该对象的所有成员变量
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
// 判断成员变量中是否有指定注解类型的注解
boolean hasAnnotation = field.isAnnotationPresent(PersonInfoAnnotation.class);
if (hasAnnotation) {
PersonInfoAnnotation personInfoAnnotation = field.getAnnotation(PersonInfoAnnotation.class);
System.out.println("名字: " + personInfoAnnotation.name() + "\n" +
"年龄: " + personInfoAnnotation.age() + "\n" +
"性别: " + personInfoAnnotation.gender());
for (String language : personInfoAnnotation.language()) {
System.out.println("课程名: " + language);
}
}
}
} // 解析方法上的注解信息
public static void parseMethodAnnotation() throws ClassNotFoundException {
Class<?> clazz = Class.forName("demo.annotation.SelfStudyCourse");
// 获取该对象的所有成员变量
Method[] methods = clazz.getMethods();
for (Method method : methods) {
// 判断方法中是否有指定注解类型的注解
boolean hasAnnotation = method.isAnnotationPresent(CourseInfoAnnotation.class);
if (hasAnnotation) {
CourseInfoAnnotation methodAnnotation = method.getAnnotation(CourseInfoAnnotation.class);
System.out.println("课程名: " +methodAnnotation.courseName() + "\n" +
"课程标签: " + methodAnnotation.courseTag() + "\n" +
"课程简介: "+ methodAnnotation.courseProfile() + "\n" +
"课程代号: " + methodAnnotation.courseIndex());
}
}
}

  注解获取属性值的底层实现,是通过JVM为注解生成代理对象。

注解的工作原理

  • 通过键值对的形式为注解属性赋值
  • 编译器检查注解的使用范围,将注解信息写入元素属性表,
  • 运行时JVM将RUNTIME的所有注解属性取出并最终存入map里
  • 创建AnnotationInvocationHandler实例并传入前面的map中
  • JVM使用JDK动态代理为注解生成代理类,并初始化对应的处理器(AnnotationInvocationHandler)
  • 调用invoke方法,通过传入方法名返回注解对应的属性值

关于Java中泛型、反射和注解的扫盲篇的更多相关文章

  1. Java中的反射和注解

    前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...

  2. 浅说Java中的反射机制(二)

    写过一篇Java中的反射机制,不算是写,应该是抄了,因为那是别人写的,这一篇也是别人写的,摘抄如下: 引自于Java基础--反射机制的知识点梳理,作者醉眼识朦胧.(()为我手记) 什么是反射? 正常编 ...

  3. 第89节:Java中的反射技术

    第89节:Java中的反射技术 反射技术是动态的获取指定的类,和动态的调用类中的内容(没有类前就可以创建对象,将对象的动作完成,这就是动态的获取指定的类). 配置文件把具体实现的类名称定义到配置文件中 ...

  4. 【Java基础】反射和注解

    前言 在Java中,反射机制和注解机制一直是一个很重要的概念,那么他们其中的原理是怎么样呢,我们不仅仅需要会使用,更要知其然而之所以然. 目录 反射机制 反射如何使用 注解定义 注解机制原理 注解如何 ...

  5. Java中泛型使用

    Java中泛型使用 泛型作用: 泛型:集合类添加对象不用强转 反射机制:将泛型固定的类的所有方法和成员全部显示出来 核心代码: ArrayList<Ls> ff=new ArrayList ...

  6. [转]Java中实现自定义的注解处理器

    Java中实现自定义的注解处理器(Annotation Processor) 置顶2016年07月25日 19:42:49 阅读数:9877 在之前的<简单实现ButterKnife的注解功能& ...

  7. java中的反射(三)

    目录 一.反射 1.class类 2.访问字段 3.调用方法 4.调用构造方法 5.获取继承对象 6.动态代理 二.sping中的反射 本篇转自:https://depp.wang/2020/05/0 ...

  8. java中的反射机制在Android开发中的用处

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反 ...

  9. 浅说Java中的反射机制(一)

    在学习传智播客李勇老师的JDBC系列时,会出现反射的概念,由于又是第一次见,不免感到陌生.所以再次在博客园找到一篇文章,先记录如下: 引用自java中的反射机制,作者bingoideas.(()为我手 ...

随机推荐

  1. 整理requests和正则表达式爬取猫眼Top100中遇到的问题及解决方案

    最近看崔庆才老师的爬虫课程,第一个实战课程是requests和正则表达式爬取猫眼电影Top100榜单.虽然理解崔老师每一步代码的实现过程,但自己敲代码的时候还是遇到了不少问题: 问题1:获取respo ...

  2. 092 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 02 static关键字 02 static关键字(中)

    092 01 Android 零基础入门 02 Java面向对象 02 Java封装 01 封装的实现 03 # 088 01 Android 零基础入门 02 Java面向对象 02 Java封装 ...

  3. 00 what is C Programming?C编程是什么?

    C语言简介 C is a programming language that lets us give a computer very specifio commands. C语言是一种编程语言,它让 ...

  4. matlab中uicontrol创建用户界面控件

    来源:https://ww2.mathworks.cn/help/matlab/ref/uicontrol.html?searchHighlight=uicontrol&s_tid=doc_s ...

  5. 用< 100行代码向EPUB或Web服务器添加视频回放

    下载source - 32.3 KB 下载latest version from GituHub 介绍 在我 在关于CodeProject的前一篇文章中,我展示了一个简单的EPUB查看器 Androi ...

  6. bash 在指定目录查找包含特定关键字的文件

    比如我们要在目录/usr/local/nginx/conf/vhost/下查找baidu.com这个关键字的文件 方法1: find /usr/local/nginx/conf/vhost/ -exe ...

  7. 多测师讲解python _练习题003_高级讲师肖sir

    python 003作业题:# 1.分别打印100以内的所有偶数和奇数并存入不同的列表当中# 2.请写一段Python代码实现删除一个list = [1, 3, 6, 9, 1, 8]# 里面的重复元 ...

  8. 用算法去扫雷(go语言)

    最初的准备 首先得完成数据的录入,及从扫雷的程序读取界面数据成为我的算法可识别的数据 其次是设计扫雷的算法,及如何才能判断格子是雷或者可以点击鼠标左键和中键. 然后将步骤2的到的结果通过我的程序实现鼠 ...

  9. centos8安装zookeeper(单机方式)

    一,下载zookeeper: 1,官网地址 http://zookeeper.apache.org/ 找到这个地址: https://mirrors.tuna.tsinghua.edu.cn/apac ...

  10. centos8上使用lsblk查看块设备

    一,查看lsblk命令所属的rpm包 [root@yjweb ~]# whereis lsblk lsblk: /usr/bin/lsblk /usr/share/man/man8/lsblk.8.g ...