Java_注解与反射

P1.注解

C1.概述

  • 注解(Annotation)

  • 作用:

    • 不是程序本身,可以对程序做出解释

      • 这点和注释(Comment)一样

    • 可以被其它程序读取

      • 比如:编译器

  • 格式:

    • @注释名

    • @注释名(value="unchecked")

  • 使用的地方:

    • package

    • class

    • method

    • field

      相当于给它们添加了额外的辅助信息;

      我们可以通过反射机制编程实现对这些元数据的访问

C2.内置注解

  • @Override

    • 定义在java.lang.Override

    • 只能修饰方法

    • 表示一个方法声明打算重写超类中的另一个方法声明

  • @Deprecated

    • 定义在java.lang.Deprecated

    • 可修饰方法、属性、类

    • 表示不鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择

  • @SupperWarnings

    • 定义在java.lang.SupperWarnings

    • 用来抑制编译时的警告信息

    • 必须要有参数

    • 例子:

      • @SupperWarnings("all")

      • @SupperWarnings("unchecked")

      • @SupperWarnings(value={"unchecked", "deprecation"})

C3.元注解

  • 元注解 => 负责注解其它注解

  • java.lang.annotation包中

  • 1) @Target

    • 描述注解的使用范围

  • 2) @Retention

    • 表示需要在什么级别保存该注释信息

      • 用于描述注解的生命周期

    • SOURCE < CLASS < RUNTIME

  • 3) @Documented

    • 说明该注解将被包含在Javadoc中

  • 4) @Inherited

    • 说明子类可以继承父类中的该注解

 package demo;
 
 import java.lang.annotation.Documented;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 @MyAnnotation
 public class Test01 {
 
  @MyAnnotation
  public void test() {
 
  }
 }
 
 @Inherited
 @Documented
 @Retention(RetentionPolicy.RUNTIME)
 @Target(value= {ElementType.TYPE, ElementType.METHOD})
 @interface MyAnnotation {
 
 }

C4.自定义注解

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

  • 自定义注释的格式:public @interface 注释名 { 定义内容 }

    • 其中的每一个方法实际上是声明了一个配置参数

      • 方法的名称 => 参数的名称

      • 返回值类型 => 参数类型

      • default => 声明参数的默认值

      • 如果只有一个参数成员,一般参数名为value

      • 注解元素必须要有值

        • 我们定义注解元素时,通常使用空字符串、0作为默认值

 package demo;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 @MyAnnotation2(age=10, schools= {})
 @MyAnnotation3("abc")
 public class Test02 {
 
  @MyAnnotation2(age=10, name="haha", schools="njcit")
  public void fun() {
 
  }
 }
 
 @Target({ ElementType.TYPE, ElementType.METHOD })
 @Retention(RetentionPolicy.RUNTIME)
 @interface MyAnnotation2 {
  String name() default "";
  int age();
  int id() default -1;
 
  String[] schools();
 }
 
 @Target({ ElementType.TYPE, ElementType.METHOD })
 @Retention(RetentionPolicy.RUNTIME)
 @interface MyAnnotation3 {
  String[] value();
 }

P2.反射

C1.概述

  • “动态语言”与“静态语言”:

    • 动态语言:

      • 在运行时可以改变其结构

        • 例如新的函数、对象,甚至代码可以被引进,已有的函数可以被删除或者其他结构上的变化

        • 即,在运行时代码可以根据某些条件改变自身接哦股

      • 如:C#、Js、PHP、Python等

    • 静态语言:

      • 运行时结构不可变的语言

      • 如:Java、C、C++

      • 准动态语言

        • Java具有一定的动态性

        • 我们可以通过反射机制获得类似动态语言的特性

  • 反射机制允许程序在执行期间,借助Reflection API取得任何类的内部信息,并直接操作任意对象的内部属性及方法

  • 加载完类后,在堆内存的方法区中就会产生一个Class类型的对象

    • 一个类只有一个Class对象

    • 该对象包含了完整的类的结构信息

      • 通过这个类能够看到类的结构

  • 优缺点:

    • 优点:

      • 可以动态实现创建对象和编译,体现出很大的灵活性

    • 缺点:

      • 对性能有影响

        • 反射基本上是一种解释操作

          • 我们告诉JVM希望它做什么,并且使它满足我们的要求

          • 这类操作往往慢于直接执行相同的操作

  • 反射相关的主要API

    • java.lang.Class

    • java.lang.reflect.Method

    • java.lang.reflect.Field

    • java.lang.reflect.Constructor

C2.理解Class类并获取Class实例

  • Class对象只能由系统建立对象

  • 一个Class对象对应的是一个加载到JVM中的一个.class文件

  • 每个类的实例都会记得自己是由哪个Class实例所生成

  • 通过Class类可以完整的得到一个类中所有被加载的结构

  • Class类是Reflection的根源,任何你想动态加载、运行的类,唯有先获得相应的Class对象

  • Class类的常用方法:

  • 哪些类型可以有Class对象?

    • class

    • interface

    • 数组

      • 只要元素类型同,即使数组长度不同,它们的Class都一样

    • enum

    • annotation

    • primitive type

    • void

C3.类的加载与ClassLoader

  • Java内存:

  • 类加载的过程

  • 什么时候发生类初始化:

 // 获取系统类的加载器
 ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
 System.out.println("<appClassLoader> " + appClassLoader);
 
 // 获取系统类加载器的父类加载器 => 扩展类加载器
 ClassLoader extClassLoader = appClassLoader.getParent();
 System.out.println("<extClassLoader> " + extClassLoader);
 
 // 获取扩展类加载器的父类加载器 => 根加载器
 // 因为是C/C++编写的,所以Java获取不到
 ClassLoader rootClassLoader = extClassLoader.getParent();
 System.out.println("<rootClassLoader> " + rootClassLoader);
 
 // 测试当前类是哪个类加载器加载的
 ClassLoader curClassLoader = Class.forName("demo.Test03").getClassLoader();
 System.out.println("<curClassLoader> " + curClassLoader);
 
 // 测试jdk内置类是哪个类加载器加载的
 ClassLoader objClassLoader = Class.forName("java.lang.Object").getClassLoader();
 System.out.println("<jdk内置类的ClassLoader> " + objClassLoader);
 
 // 如何获得系统类加载器可以加载的路径
 System.out.println("系统类加载器可以加载的路径");
 System.out.println(System.getProperty("java.class.path"));
 <appClassLoader>
 sun.misc.Launcher$AppClassLoader@73d16e93
 <extClassLoader>
 sun.misc.Launcher$ExtClassLoader@15db9742
 <rootClassLoader>
 null
 <curClassLoader>
 sun.misc.Launcher$AppClassLoader@73d16e93
 <jdk内置类的ClassLoader>
 null
 系统类加载器可以加载的路径
 D:Program DataworkspaceEclipse2.NewStudy_Java7.Annotationin

C4.创建运行时类的对象

  • 调用Class对象的newInstance()方法

    • 类必须有一个无参的构造函数

    • 类的构造函数的访问权限必须要足够

  • 如果反射比较多的话,建议关闭“检测”,这样能够提升效率

C5.获取运行时类的完整结构

  • 通过反射获取完整的运行时类结构

  • Field、Method、Constructor、Superclass、Interface、Annotation......

C6.调用运行时类的指定结构

反射操作泛型

  • 泛型 => 一种约束机制

    • Java采用的是泛型擦除机制来引入泛型

    • 仅仅是给编译器javac使用的

      • 一旦编译完成,所有和泛型有关的类型全部擦除

    • 确保数据的安全性和免除强制类型

  • 为了通过反射操作这些类型,Java新增了ParameterizedType、GenericArrayType、TypeVariable、WildcardType几种类型,用于代表不能被归一到Class类中的类型,但是又和原类型齐名的类型

    • ParameterizedType

      • 表示一种参数化类型,如Collection<String>

    • GenericArrayType

      • 表示一种元素类型是参数化类型或者类型变量的数组类型

    • TypeVariable

      • 各种类型变量的公共父接口

    • WildcardType

      • 代表一种通配符类型表达式

  • 获得方法泛型参数的类型:method.getGenericParameterTypes();

 package demo;
 
 import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.util.Map;
 
 public class Test05 {
  public void test01(Map<String, User> map, User<Integer> user) {
 
  }
 
  public Map<String, User> test02() {
  return null;
  }
 
  public static void main(String[] args) throws NoSuchMethodException, SecurityException {
  Method method = Test05.class.getMethod("test01", Map.class, User.class);
 
  Type[] genericParameterTypes = method.getGenericParameterTypes();
  for (Type type : genericParameterTypes) {
  System.out.println(" #" + type);
  if (type instanceof ParameterizedType) {
  Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
  for (Type type2 : actualTypeArguments) {
  System.out.println(type2);
  }
  }
  }
 
  Method method2 = Test05.class.getMethod("test02", null);
  Type genericReturnType = method2.getGenericReturnType();
  System.out.println(" #" + genericReturnType);
  if (genericReturnType instanceof ParameterizedType) {
  Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
  for (Type type2 : actualTypeArguments) {
  System.out.println(type2);
  }
  }
  }
 }

反射操作注解

  • getAnnotations

  • geAnnotation

  • ORM

    • Object Relationship Mapping => 对象关系映射

 package demo;
 
 import java.lang.annotation.Annotation;
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.lang.reflect.Field;
 
 public class Test06 {
  public static void main(String[] args) throws ClassNotFoundException {
  Class<?> cls = Class.forName("demo.Student");
 
  System.out.println(" // 获取Student类的所有注解");
  Annotation[] typeAnnotations = cls.getAnnotations();
  for (Annotation annotation : typeAnnotations) {
  System.out.println(annotation);
  }
 
  System.out.println(" // 获取指定注解的值");
  TypeAnnotation typeAnnotation = cls.getAnnotation(TypeAnnotation.class);
  String value = typeAnnotation.value();
  System.out.println(value);
 
  System.out.println(" // 获取Student类属性的所有注解");
  Field[] declaredFields = cls.getDeclaredFields();
  for (Field field : declaredFields) {
  Annotation[] fieldAnnotations = field.getAnnotations();
  for (Annotation annotation : fieldAnnotations) {
  System.out.println(annotation);
  System.out.println(((FieldAnnotation)annotation).dbName());
  System.out.println(((FieldAnnotation)annotation).dbType());
  System.out.println(((FieldAnnotation)annotation).length());
  }
  }
  }
 }
 
 @Deprecated
 @TypeAnnotation("db_user")
 class Student {
  @FieldAnnotation(dbName = "t_id", dbType = "varchar", length = 10)
  private String id;
  @FieldAnnotation(dbName = "t_gender", dbType = "varchar", length = 2)
  private String gender;
 
  public Student(String id, String gender) {
  super();
  this.id = id;
  this.gender = gender;
  }
 
  public Student() {
  super();
  }
 
  public String getId() {
  return id;
  }
 
  public void setId(String id) {
  this.id = id;
  }
 
  public String getGender() {
  return gender;
  }
 
  public void setGender(String gender) {
  this.gender = gender;
  }
 
  @Override
  public String toString() {
  return "Student [id=" + id + ", gender=" + gender + "]";
  }
 }
 
 @Target(ElementType.TYPE)
 @Retention(RetentionPolicy.RUNTIME)
 @interface TypeAnnotation {
  String value();
 }
 
 @Target(ElementType.FIELD)
 @Retention(RetentionPolicy.RUNTIME)
 @interface FieldAnnotation {
  String dbName();
 
  String dbType();
 
  int length();
 }

 

原文地址:https://www.cnblogs.com/daheww/p/10654580.html