注解与反射

亦凉 2023-10-01 16:56 44阅读 0赞

注解

什么是注解

  • Annotation(注解)是从JDK5.0开始引入的新技术
  • 注解可以被其他程序(如:编译器等)读取,不是程序本身,可以对程序做出解释
  • 注解以**“@注释名”**在代码中存在,还可以添加一些参数值
  • 我们可以通过反射机制编程实现对这些元数据的访问

内置注解

  • @Override:定义在java.lang.Override中,此注释只适用于修辞方法,表示一个方法声明打算重写超类中的另外一个方法声明
  • @Deprecated:定义在java.lang.Deprecated中,此注释可以用于修辞方法,属性,类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择
  • @SuppressWarnings:定义在java.lang.SuppressWarnings中,用来一直编译时的警告信息

    • 与前面两个注释有所不同,你需要添加一个参数才能正确使用,这些参数都是已经定义好了的,我们选择性的实用就好了

      • @SuppressWarings(“all”)
      • @SuppressWarings(“unchecked”)
      • @SuppressWarings(“value={“unchecked”,deprecation})
      • 等等

元注解

元注解的作用是辅助注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他的annotation类型作说明,在java.lang.annotation包中

  • @Target:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
  • @Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期

    • (SOURCE<CLASS<RUNTIME)
  • @Document:说明该注解将被包含在javadoc中
  • @Inherited:说明子类可以继承父类中的该注解

自定义注解

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

  1. //自定义注解
  2. public class Test01 {
  3. @MyAnnotation(age = 18)//如果自定义注解中没有默认值,则必须要输入值
  4. public void test(){
  5. }
  6. }
  7. @Target({
  8. ElementType.TYPE,ElementType.METHOD})
  9. @Retention(RetentionPolicy.RUNTIME)
  10. @interface MyAnnotation{
  11. //注解的参数:参数类型+参数名();
  12. String name() default "";
  13. int age();
  14. int id() default -1;
  15. String[] schools() default {
  16. "lzj","hgd"};
  17. }

反射

反射机制概述

  • Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象的内部属性及方法

    1. //通过反射获取类的class对象
    2. Class c = Class.forName("java.lang.String");
  • 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象) ,这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一 面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射

    正常方式:引入需要的“包类名称”—>通过new实例化—>取得实例化对象

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

  • 优点:可以实现动态创建对象和编译,体现出很大的灵活性
  • 缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求,这类操作总是慢于直接执行相同的操作

反射相关的主要API

  • java.lang.Class :代表一个类
  • java.lang.reflect.Method :代表类的方法
  • java.lang.eflect.Field :代表类的成员变量
  • java.lang.reflect.Constructor :代表类的构造器

Class类

对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个结构(class/interface/enum/annotation/primitive type/void/[])的有关信息。

  • Class 本身也是一个类
  • Class 对象只能由系统建立对象
  • 一个加载的类在JVM中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一 个class文件
  • 每个类的实例都会记得自己是由哪个Class实例所生成
  • 通过Class可以完整地得到一个类中的所有被加载的结构
  • Class类 是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象
获取Class类的实例
  1. //若已知具体的类,通过class属性获取,该方法最为安全可靠,程序的性能最高
  2. Class clazz = Person.class;
  3. //一直某个类的实例,调用该实例的getClass()方法获取Class对象
  4. Class clazz = person.getClass();
  5. //已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取
  6. Class clazz = Class.forName("demo01.Student");
  7. //内置基本数据类型可以直接用类名.Type
  8. Integer.Type

获取类运行时的结构

  1. //获取类运行时的结构
  2. public class Test02 {
  3. public static void main(String[] args) throws ClassNotFoundException {
  4. Class aClass = Class.forName("反射.Stud");
  5. //获得类的名字
  6. System.out.println(aClass.getName());//获得包名+类名
  7. System.out.println(aClass.getSimpleName());//获得类名
  8. //获得类的属性
  9. System.out.println("======================");
  10. Field[] fields = aClass.getFields();//只能找到public属性
  11. Field[] declaredFields = aClass.getDeclaredFields();//找到全部是属性
  12. //获得类的方法
  13. System.out.println("=====================");
  14. Method[] methods = aClass.getMethods();//获得本类及父类的所有方法
  15. Method[] declaredMethods = aClass.getDeclaredMethods();//获得本类的所有方法
  16. //获得构造器
  17. System.out.println("=====================");
  18. Constructor[] constructors = aClass.getConstructors();//获得全部的构造器
  19. Constructor[] declaredConstructors = aClass.getDeclaredConstructors();//获得本类全部的构造器
  20. }
  21. }

通过反射动态的创建对象

  1. public class User {
  2. private String name;
  3. private int id;
  4. private int age;
  5. public User() {
  6. }
  7. public User(String name, int id, int age) {
  8. this.name = name;
  9. this.id = id;
  10. this.age = age;
  11. }
  12. public String getName() {
  13. return name;
  14. }
  15. public void setName(String name) {
  16. this.name = name;
  17. }
  18. public int getId() {
  19. return id;
  20. }
  21. public void setId(int id) {
  22. this.id = id;
  23. }
  24. public int getAge() {
  25. return age;
  26. }
  27. public void setAge(int age) {
  28. this.age = age;
  29. }
  30. @Override
  31. public String toString() {
  32. return "User{" +
  33. "name='" + name + '\'' +
  34. ", id=" + id +
  35. ", age=" + age +
  36. '}';
  37. }
  38. }
  39. //动态的创建对象,通过反射
  40. public class Test03 {
  41. public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
  42. //获得class对象
  43. Class<?> aClass = Class.forName("反射.User");
  44. //构造一个对象
  45. User user = (User) aClass.newInstance();//本质是调用了类的无参构造器
  46. System.out.println(user);
  47. //通过构造器创建对象
  48. Constructor<?> constructor = aClass.getDeclaredConstructor(String.class, int.class, int.class);
  49. User user1 = (User) constructor.newInstance("lzj", 01, 18);
  50. System.out.println(user1);
  51. //通过反射调用普通方法
  52. User user3 = (User) aClass.newInstance();
  53. //通过反射获取一个方法
  54. Method setName = aClass.getDeclaredMethod("setName", String.class);
  55. //invoke:激活的意思
  56. //(对象,“方法的值”)
  57. setName.invoke(user3,"lzj");
  58. System.out.println(user3.getName());
  59. //通过反射操作属性
  60. User user4 = (User) aClass.newInstance();
  61. Field name = aClass.getDeclaredField("name");
  62. //不能直接操作私有属性,我们需要关闭程序的安全检测,属性或方法的setAccessible(true)
  63. name.setAccessible(true);
  64. name.set(user4,"lzj");
  65. System.out.println(user4.getName());
  66. }
  67. }

性能对比分析

  1. public class Test4 {
  2. //普通方式调用
  3. public static void test01(){
  4. User user = new User();
  5. long startTime = System.currentTimeMillis();
  6. for (int i = 0; i < 1000000000; i++) {
  7. user.getName();
  8. }
  9. long endTime = System.currentTimeMillis();
  10. System.out.println("普通方法执行10亿次:"+(endTime-startTime)+"ms");
  11. }
  12. //反射方式调用
  13. public static void test02() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
  14. User user = new User();
  15. Class c1 = user.getClass();
  16. Method declaredMethod = c1.getDeclaredMethod("getName", null);
  17. long startTime = System.currentTimeMillis();
  18. for (int i = 0; i < 1000000000; i++) {
  19. declaredMethod.invoke(user,null);
  20. }
  21. long endTime = System.currentTimeMillis();
  22. System.out.println("反射调用方式执行10亿次:"+(endTime-startTime)+"ms");
  23. }
  24. //反射方式调用,关闭检测
  25. public static void test03() throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
  26. User user = new User();
  27. Class c1 = user.getClass();
  28. Method declaredMethod = c1.getDeclaredMethod("getName", null);
  29. declaredMethod.setAccessible(true);
  30. long startTime = System.currentTimeMillis();
  31. for (int i = 0; i < 1000000000; i++) {
  32. declaredMethod.invoke(user,null);
  33. }
  34. long endTime = System.currentTimeMillis();
  35. System.out.println("关闭检测反射调用方式执行10亿次:"+(endTime-startTime)+"ms");
  36. }
  37. public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
  38. test01();
  39. test02();
  40. test03();
  41. }
  42. }

通过反射操作注解

  1. //反射操作注解
  2. public class Test5 {
  3. public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
  4. Class<?> c1 = Class.forName("反射.Student2");
  5. //通过反射获得注解
  6. Annotation[] annotations = c1.getAnnotations();
  7. for (Annotation annotation : annotations) {
  8. System.out.println(annotation);
  9. }
  10. //获得注解的value值
  11. TableLzj annotation = c1.getAnnotation(TableLzj.class);
  12. String value=annotation.value();
  13. System.out.println(value);
  14. //获得类指定的注解
  15. Field name = c1.getDeclaredField("name");
  16. FiledLzj annotation1 = name.getAnnotation(FiledLzj.class);
  17. System.out.println(annotation1.columnName());
  18. System.out.println(annotation1.length());
  19. System.out.println(annotation1.type());
  20. }
  21. }
  22. @TableLzj("db_student")
  23. class Student2{
  24. @FiledLzj(columnName = "db_id",type = "int",length = 10)
  25. private int id;
  26. @FiledLzj(columnName = "db_age",type = "int",length = 10)
  27. private int age;
  28. @FiledLzj(columnName = "db_name",type = "varchar",length = 3)
  29. private String name;
  30. public Student2() {
  31. }
  32. public Student2(int id, int age, String name) {
  33. this.id = id;
  34. this.age = age;
  35. this.name = name;
  36. }
  37. public int getId() {
  38. return id;
  39. }
  40. public void setId(int id) {
  41. this.id = id;
  42. }
  43. public int getAge() {
  44. return age;
  45. }
  46. public void setAge(int age) {
  47. this.age = age;
  48. }
  49. public String getName() {
  50. return name;
  51. }
  52. public void setName(String name) {
  53. this.name = name;
  54. }
  55. @Override
  56. public String toString() {
  57. return "Student2{" +
  58. "id=" + id +
  59. ", age=" + age +
  60. ", name='" + name + '\'' +
  61. '}';
  62. }
  63. }
  64. //类名的注解
  65. @Target(ElementType.TYPE)
  66. @Retention(RetentionPolicy.RUNTIME)
  67. @interface TableLzj{
  68. String value();
  69. }
  70. //属性的注解
  71. @Target(ElementType.FIELD)
  72. @Retention(RetentionPolicy.RUNTIME)
  73. @interface FiledLzj{
  74. String columnName();
  75. String type();
  76. int length();
  77. }

发表评论

表情:
评论列表 (有 0 条评论,44人围观)

还没有评论,来说两句吧...

相关阅读

    相关 注解反射

    注解(Annotation)是Java中的一种元数据,它提供了一种为程序元素(类、方法、变量等)添加元数据的方式。注解可以用来描述程序元素的特性、用途和约束条件等信息。Java

    相关 注解反射

    注解(Annotation)是Java中的一种元数据,它提供了一种为程序元素(类、方法、变量等)添加元数据的方式。注解可以用来描述程序元素的特性、用途和约束条件等信息。Java

    相关 注解反射

    注解 什么是注解 Annotation(注解)是从JDK5.0开始引入的新技术 注解可以被其他程序(如:编译器等)读取,不是程序本身,可以对程序做出解释

    相关 反射注解

    反射与注解 一、反射 1. 使用反射机制可以动态的获取当前class的信息,比如方法的信息、注解信息、方法的参数、属性 2. 反射目的:方便开发者对框架的拓展,

    相关 JAVA反射注解

    JAVA反射与注解 前言 现在在我们构建自己或公司的项目中,或多或少都会依赖几个流行比较屌的第三方库,比如:Butter Knife、Retrofit 2、Dagge