liang-chen-fly

Java注解和反射

注解

  • Annotation

  1. 不是程序本身, 可以对程序作出解释

  2. 可以被其他程序(比如: 编译器)读取

内置注解

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

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

  • @SuppressWarnings 用来抑制编译时的警告信息, 需要参数

    • @SuppressWarnings ("all")

    • @SuppressWarnings ("unchecked")

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

    • ...

元注解

  • 负责注解其他注解 meta-annotation

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

  2. @Retention 表示需要在什么级别保存该注释信息, 用于描述注解的生命周期

    1. SOURCE < CLASS < RUNTIME

  3. @Documented 说明该注解将包含在javadoc中

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

package com.cyz;

import java.lang.annotation.*;

//测试元注解
public class Test02 {

  @MyAnnotation
  public void test(){

  }

}

//定义一个注解
//@Target 表示这个注解用在什么上 方法 类 字段
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//@Retention 表示注解在什么时候地方生效 运行时
//runtime > class > sources
@Retention(value = RetentionPolicy.RUNTIME)
@Documented//表示是否将我们的注解生成在JAVAdoc中
@Inherited//子类可以继承父类的注解
@interface MyAnnotation{

}

自定义注解

package com.cyz;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class Test03 {

   //注解显示赋值 如果没有默认值, 我们就必须给注解赋值 没有顺序
   @MyAnnotation2(age = 19, name = "chen")
   public void test(){

  }

   @MyAnnotation3("chen")//属性为value时, 可以省略
   public void test2(){

  }

}

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
   //注释的参数: 参数类型 + 参数名();
   String name() default "";
   int age();
   int id() default -1;//如果默认值为-1为不存在

   String[] schools() default {"喜碧","大写"};
}

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
   String value();//只有一个参数使用value
}

反射

  • 是java被视为动态语言的关键

  • 反射机制允许程序在执行期借助于Refletion API取得任何类的内部信息

  • 并能直接操作任意对象的内部属性及方法

加载完类之后, 在堆内存的方法区中就产生了以个Class类型的对象(一个类只有一个Class对象),
这个对象就包含了完整的类的结构信息. 我们可以通过这个对象看到类的结构. 这个对象就像一面镜子, 透过这个镜子看到类的结构, 所以, 我们新乡的称之为: 反射
正常方式:  引入需要的"包类"名称--->通过new实例化--->取得实例化对象

反射方式: 实例化对象---->getClass()方法----->得到完整的"包类"名称

反射机制提供的功能

  1. 运行时判断任意一个对象所属的类

  2. 运行时构造任意一个类的对象

  3. 运行时判断任意一个类所具有的的成员变量和方法

  4. 运行时获取泛型信息

  5. 运行时调用任意一个对象的成员变量和方法

  6. 运行时处理注解

  7. 生成动态代理

  8. ...

优点

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

缺点

  • 对性能影响, 使用反射基础上是一种解释操作, 我们可以告诉JVM, 我们希望做什么 并且他满足我们的要求, 这类操作总是慢于直接执行相同的操作

主要API

  • java.lang.Class 代表一个类

  • java.lang.reflect.Method 代表类的方法

  • java.lang.reflect.Field 代表类的成员变量

  • java.lang.reflect.Constructor 代表类的构造器

package com.cyz.demo02;

public class Test02 {
   public static void main(String[] args) throws ClassNotFoundException {
       //通过反射获取类的Class对象
       Class c1 = Class.forName("com.cyz.demo02.Test02");
       System.out.println(c1);

       Class c2 = Class.forName("com.cyz.demo02.Test02");
       Class c3 = Class.forName("com.cyz.demo02.Test02");
       Class c4 = Class.forName("com.cyz.demo02.Test02");

       //一个类在内存中只有一个Class对象
       //一个类被加载后, 类的整个结构刽被封装在Class对象中
       System.out.println(c2.hashCode());
       System.out.println(c3.hashCode());
       System.out.println(c4.hashCode());//三者相等
  }
}


//实体类
class User{
   private String name;
   private int id;
   private int age;

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

   public String getName() {
       return name;
  }

   public void setName(String name) {
       this.name = name;
  }

   public int getId() {
       return id;
  }

   public void setId(int id) {
       this.id = id;
  }

   public int getAge() {
       return age;
  }

   public void setAge(int age) {
       this.age = age;
  }

   @Override
   public String toString() {
       return "User{" +
               "name=\'" + name + \'\\'\' +
               ", id=" + id +
               ", age=" + age +
               \'}\';
  }
}

Class类

  1. Class本身也是一个类

  2. Class 对象只能有系统建立对象

  3. 一个加载的类在JVM中只会有一个Class类

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

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

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

  7. Class类是Reflection的根源, 针对任何你想动态加载, 运行的类, 唯有先获取响应的Class对象

常用方法

方法名 功能说明
static Class forName(String name) 返回指定类名name的Class对象
Object newInstance() 调用缺省构造函数, 返回Class对象的一个实例
getName() 返回此Class对象所表示的实体(类, 接口, 数组类或void) 的名称
Class getSuperClass() 返回当前Class对象的父类的Class对象
Class[] getinterfaces() 获取当前Class对象的接口
ClassLoader getClassLoader() 返回该类的加载器
Constructor[] getConstructors() 返回一个包含某些Constructor对象的数组
Method getMothed(String name, Class.. T) 返回一个Method对象, 此对象的形参类型为paramType
Field[] getDeclaredFields() 返回Field对象的一个数组
package com.cyz.demo03;

public class Test03 {
   public static void main(String[] args) throws ClassNotFoundException {
       Person person = new Student();
       System.out.println("这个人是:"+person.name);

       //方式一 通过对象获取
       Class c1 = person.getClass();
       System.out.println(c1.hashCode());

       //方式二 forname获取   异常抛出
       Class c2 = Class.forName("com.cyz.demo03.Student");
       System.out.println(c2.hashCode());

       //方式三 通过类名.class获取
       Class c3 = Student.class;
       System.out.println(c3.hashCode());

       //方式四: 基本内置类的包装类都有一个Type属性
       Class c4 = Integer.TYPE;
       System.out.println(c4);

       //获取父类类型
       Class c5 = c1.getSuperclass();
       System.out.println(c5);
  }

}


class Person{
   public String name;

   public Person(){

  }
   public Person(String name){
       this.name = name;
  }

   @Override
   public String toString() {
       return "Person{" +
               "name=\'" + name + \'\\'\' +
               \'}\';
  }
}

class Student extends Person{
   public Student(){
       this.name = "学生";
  }
}

class Teacher extends Person{
   public Teacher(){
       this.name = "老师";
  }
}

那些类型可以有Class对象

  1. class: 外部类, 成员(成员内部类, 静态内部类), 局部内部类, 匿名内部类

  2. interface: 接口

  3. []: 数组

  4. enum: 枚举

  5. annotation: 注解@interface

  6. primitive type: 基本数据类型

  7. void

package com.cyz.demo03;

import java.lang.annotation.ElementType;

public class Test04 {
   public static void main(String[] args) {
       Class c1 = Object.class;//类
       Class c2 = Comparable.class;//接口
       Class c3 = String[].class;//一维数组
       Class c4 = int[][].class;//二维数组
       Class c5 = Override.class;//注解
       Class c6 = ElementType.class;//枚举
       Class c7 = Integer.class;//基本数据类型
       Class c8 = void.class;//void
       Class c9 = Class.class;//Class

      System.out.println(c1);
      System.out.println(c2);
      System.out.println(c3);
      System.out.println(c4);
      System.out.println(c5);
      System.out.println(c6);
      System.out.println(c7);
      System.out.println(c8);
      System.out.println(c9);

//       class java.lang.Object
//       interface java.lang.Comparable
//       class [Ljava.lang.String;
//       class [[I
//       interface java.lang.Override
//       class java.lang.annotation.ElementType
//       class java.lang.Integer
//       void
//       class java.lang.Class

//只要元素类型和维度一样, 就是同一个Class
       int[] a = new int[10];
       int[] b = new int[100];
       System.out.println(a.getClass().hashCode());
       System.out.println(b.getClass().hashCode());

  }
}

类的加载

  • 加载: 将class字节码的内容加载到内存中, 并将这些静态数据装换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang,Class对象

  • 连接: 将Java类的二进制代码合并到JVM的运行状态之中的过程

    • 验证: 验证类信息符合规范

    • 准备: 在方法区中为类分配内存和默认初始化值

    • 解析: 虚拟机常量池内的符号引用(常量名) 替换为直接引用(地址) 的过程

  • 初始化:

    • 执行类构造器

    • 父类必须先有初始化

    • 正确加锁和同步

什么时候会发生类的初始化

类的主动引用(一定会发生类的初始化)

  1. 当虚拟机启动时, 先初始化main方法所在的类

  2. new一个类的对象

  3. 调用类的静态成员(除了final常量) 和静态方法

  4. 使用java.lang.reflect包的方法对类进行反射调用

  5. 当初始化一个类, 如果其父类没有被初始化, 则先会初始他的父类

类的被动引用 (不会发生类的初始化)

  1. 当访问一个静态域时, 只要真正声明这个域的类才会初始化. 如: 当通过子类引用父类的静态变量, 不会导致子类初始化

  2. 通过数组定义类引用, 不会触发此类的初始化

  3. 引用常量不会触发此类的初始化(常量在连接阶段就存入调用类的常量池中了)

package com.cyz.demo03;

public class Test06 {

   static {
       System.out.println("Main类被加载了");
  }

   public static void main(String[] args) throws ClassNotFoundException {
       //主动引用
//       Son son = new Son();
//       Main类被加载了
//       类被加载
//       子类被加载


       //反射 会产生主动引用
//       Class.forName("com.cyz.demo03.Son");
//       Main类被加载了
//       父类被加载
//       子类被加载

       //不会产生类的引用
       //静态域
//       System.out.println(Son.b);
//       Main类被加载了
//               父类被加载
//       2

       //数组
//       Son[] array = new Son[5];
       //Main类被加载了

       //常量
       System.out.println(Son.M);
//       Main类被加载了
//       1

  }

}

class Father{
   static int b = 2;

   static {
       System.out.println("父类被加载");
  }
}

class Son extends Father{

   static {
       System.out.println("子类被加载");
       m = 300;
  }

   static int m = 100;
   static final int M = 1;
}

类加载器

  • 引导类加载器

  • 扩展类加载器

  • 系统类加载器

类是有缓存的

获得类的信息

package com.cyz.demo03;

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.cyz.demo03.User");

    User user = new User();
    Class c2 = user.getClass();

    //获得类的名字
    System.out.println(c1.getName());//获得包名+类名
    System.out.println(c1.getSimpleName());//获得类名

    System.out.println(c2.getName());//获得包名+类名
    System.out.println(c2.getSimpleName());//获得类名

    //获得类的属性
    Field[] fields = c1.getFields();//获取public属性
    for (Field field : fields){
        System.out.println(field);
    }

    Field[] fields2 = c1.getDeclaredFields();//获取所有属性
    for (Field field : fields2){
        System.out.println(field);
    }

    //获取指定属性 同样getFields只能 访问public
    Field name = c1.getDeclaredField("name");
    System.out.println(name);

    //获取类的方法
    Method[] methods = c1.getMethods();//获得本类及其父类的public方法
    for (Method method : methods){
        System.out.println(method);
    }

    System.out.println("=================");

    Method[] declaredMethods = c1.getDeclaredMethods();//获得本类的所以方法
    for (Method method : declaredMethods){
        System.out.println(method);
    }

    //获得指定的方法
    Method getName = c1.getMethod("getName", null);
    System.out.println(getName);

    Method setName = c1.getMethod("setName", String.class);
    System.out.println(setName);



    System.out.println("========================");
    //获取指定的构造器
    Constructor[] constructors = c1.getConstructors();//获取public的构造方法
    for (Constructor constructor : constructors){
        System.out.println(constructor);
    }

    System.out.println("========================");
    Constructor[] constructors2 = c1.getDeclaredConstructors();//获取所有的构造方法
    for (Constructor constructor : constructors2){
        System.out.println(constructor);
    }

    //获取指定的构造器
    Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
    System.out.println(declaredConstructor);
}

}

class User{
private String name;
private int id;
private int age;

public User(){

}

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

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

@Override
public String toString() {
    return "User{" +
            "name=\'" + name + \'\\'\' +
            ", id=" + id +
            ", age=" + age +
            \'}\';
}

}

动态创建对象的方法

package com.cyz.demo04;

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

//动态创建对象 通过反射
public class Test09 {

public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
    //获得class对象
    Class c1 = Class.forName("com.cyz.demo04.User");

    //构造一个对象
    User user = (User)c1.newInstance();//本质是调用无参构造
    System.out.println(user);

    //通过构造器创建对象
    Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
    User chen = (User)declaredConstructor.newInstance("chen", 001, 18);
    System.out.println(chen);

    //通过反射调用普通方法
    Method setName = c1.getDeclaredMethod("setName", String.class);
    //invoke 激活
    //{对象, "方法的值"}
    setName.invoke(user,"jack");
    System.out.println(user.getName());

    //通过反射操作属性  不能直接操作私有属性 需要关闭安全监测
    Field name = c1.getDeclaredField("name");
    //关闭安全监测   可以提高反射效率
    name.setAccessible(true);
    name.set(user,"mark");
    System.out.println(user.getName());
}

}

class User {
private String name;
private int id;
private int age;

public User() {

}

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

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public int getAge() {
    return age;
}

public void setAge(int age) {
    this.age = age;
}

@Override
public String toString() {
    return "User{" +
            "name=\'" + name + \'\\'\' +
            ", id=" + id +
            ", age=" + age +
            \'}\';
}

}

性能对比分析

package com.cyz.demo04;

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

public class Test10 {

//通过普通方式创建
public static void test01(){
    User user = new User();
    long startTime = System.currentTimeMillis();

    for (int i = 0; i &lt; 100000000; i++){
        user.getName();
    }

    long endTime = System.currentTimeMillis();

    System.out.println("普通方式获取10亿次:"+(endTime-startTime)+"ms");
}

//通过反射方式调用
public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    User user = new User();
    Class c1 = user.getClass();

    Method getName = c1.getDeclaredMethod("getName", null);
    long startTime = System.currentTimeMillis();

    for (int i = 0; i &lt; 100000000; i++){
        getName.invoke(user,null);
    }

    long endTime = System.currentTimeMillis();

    System.out.println("反射方式获取10亿次:"+(endTime-startTime)+"ms");
}

//反射方式调用 关闭检查
public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    User user = new User();
    Class c1 = user.getClass();

    Method getName = c1.getDeclaredMethod("getName", null);
    getName.setAccessible(true);

    long startTime = System.currentTimeMillis();

    for (int i = 0; i &lt; 100000000; i++){
        getName.invoke(user,null);
    }

    long endTime = System.currentTimeMillis();

    System.out.println("关闭检查获取10亿次:"+(endTime-startTime)+"ms");
}

public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
    test01();
    test02();
    test03();
}

}

//普通方式获取10亿次:5ms
//反射方式获取10亿次:505ms
//关闭检查获取10亿次:228ms

获取泛型信息

package com.cyz.demo04;

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&lt;String, User&gt; map, List&lt;User&gt; list) {
    System.out.println("test01");
}

public Map&lt;String, User&gt; test02() {
    System.out.println("test02");
    return null;
}

public static void main(String[] args) throws NoSuchMethodException {
    Method method = Test11.class.getMethod("test01", Map.class, List.class);
    Type[] genericParameterTypes = method.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);
            }
        }
    }

    System.out.println("==============");

    method = Test11.class.getMethod("test02", null);
    Type genericParameterType = method.getGenericReturnType();
    if (genericParameterType instanceof ParameterizedType) {
        Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
        for (Type actualTypeArgument : actualTypeArguments) {
            System.out.println(actualTypeArgument);
        }
    }
}

}

获取注解信息

  • 通过注解和反射王城类和表结构的映射关系

package com.cyz.demo04;

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

public class Test12 {
   public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
       Class c1 = Class.forName("com.cyz.demo04.Student");

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

       //获得注解的value的值
       Tablejack tablejack = (Tablejack)c1.getAnnotation(Tablejack.class);
       String value = tablejack.value();
       System.out.println(value);


       //获得指定的注解
       Field f = c1.getDeclaredField("name");
       Fieldjack annotation = f.getAnnotation(Fieldjack.class);
       System.out.println(annotation.columnName());
       System.out.println(annotation.type());
       System.out.println(annotation.length());
  }

//   @com.cyz.demo04.Tablejack(value=db_student)
//   db_student
//           db_name
//   varchar
3


}

@Tablejack("db_student")
class Student{

   @Fieldjack(columnName = "db_id",type = "int",length = 10)
   private int id;
   @Fieldjack(columnName = "db_age",type = "int",length = 10)
   private int age;
   @Fieldjack(columnName = "db_name",type = "varchar",length = 3)
   private String name;

   public Student() {
  }

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

   public int getId() {
       return id;
  }

   public void setId(int id) {
       

分类:

技术点:

相关文章:

  • 2021-11-20
  • 2021-07-22
  • 2020-12-28
  • 2021-04-08
  • 2021-08-16
  • 2021-05-24
  • 2021-11-22
猜你喜欢
  • 2019-08-11
  • 2021-07-19
  • 2021-12-21
  • 2022-01-12
  • 2021-12-16
  • 2021-09-22
  • 2020-07-30
相关资源
相似解决方案