精华内容
下载资源
问答
  • 一种基于Java注解和反射机制的Excel文件读写操作方法.pdf
  • java注解和反射的个人学习笔记
  • Java注解和反射机制

    千次阅读 2019-05-08 14:37:31
    简单学习同时练习打字 从注解(Annotation)开始 简单介绍: 一、不是程序本身,对程序作出一定的解释;...反射机制读取注解: 简单测试类: public class TestClass { private String name; private Stri...

    简单学习同时练习打字

    从注解(Annotation)开始

    简单介绍:

    一、不是程序本身,对程序作出一定的解释;(这一点与注释相同)

    二、可以被其他程序读取(如编译器),便于编译器的测试和验证,存储有关程序的额外信息;

    反射机制读取注解:

    简单测试类:

    public class TestClass {
        private String name;
        private String id;
        int address;
    }
    

    定义注解便于对测试类进行解析:

    @Target(value = {ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ClassAnnotation {
          String value();
    
    }
    

    在测试类上添加注解

    @ClassAnnotation("Table")    //类与数据库中的表对应
    public class TestClass {
        private String name;
        private String id;
        int address;
    }
    

    定义注解便于对属性进行解析

    @Target(value = {ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface PropertyAnnotation {
        String  columnName();              //表中的列名(对应类中的属性名)
        String  type();                          //类型
        int length();                             //长度
    }
    

    在属性上添加注解

    @ClassAnnotation("Table")    //类与数据库中的表对应
    public class TestClass {
        @PropertyAnnotation(columnName = "name",type = "String",length = 10)
        private String name;
        private String id;
        int address;
    }

    编写实现类通过反射获取注解,并且获取属性注解和属性的详细信息

    public class Demo {
    
        public static void main(String[] args) {
            try {
                Class clazz  = Class.forName("com.zjf.Ann.TestClass");
                Annotation[] annotations = clazz.getAnnotations();                 //通过反射获取注解
               //获得类的所有注解
                for(Annotation a : annotations){
                    System.out.println(a);
                }
                //获得类的指定注解
                ClassAnnotation ca = (ClassAnnotation) clazz.getAnnotation(ClassAnnotation.class);
                System.out.println(ca.value());
    
                 //获得属性的注解
                Field f = clazz.getDeclaredField("name");
                PropertyAnnotation pa = f.getAnnotation(PropertyAnnotation.class);
                System.out.println(pa);                               
                //获取详细信息
                System.out.println(pa.columnName()+" ----- "+ pa.type()+"-------"+pa.length());
                }catch (Exception e){
                 e.printStackTrace();
            }
        }
    }
    

    通过反射机制和注解,可以获取与类相对应的数据库中的表的详细信息,从而构造JDBC语句执行sql操作

    反射

    简单介绍:

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

    Class对象的获取:

    1、通过 Object 类中的 getClass() 方法,想要用这种方法必须要明确具体的类并且创建该类的对象。

    2、通过静态属性.class 来获取对应的 Class 对象。需要要明确到类才能调用类中的静态成员。

    3、通过给定类的字符串名称就可以获取该类的字节码对象,通过 Class.forName() 方法完成。

    获取类的信息:

    Class 类与 java.lang.reflect 类库一起对反射的概念进行了支持,该类库包含了 Field,Method,Constructor 类 (每个类都实现了 Member 接口)。这些类型的对象时由 JVM 在运行时创建的,用以表示未知类里对应的成员。

    可以使用 Constructor 创建新的对象,用 get() 和 set() 方法读取和修改与 Field 对象关联的字段,用 invoke() 方法调用与 Method 对象关联的方法。

    通过调用 getFields(),getMethods() 和 getConstructors() 等方法返回表示字段,方法,以及构造器的对象的数组。

    这样匿名对象的信息就能在运行时被完全确定下来,而在编译时不需要知道任何事情。

    参考链接

    https://www.cnblogs.com/zhaoguhong/p/6937364.html

    https://blog.csdn.net/codejas/article/details/78635926

    展开全文
  • 关于反射和注解的的源码,包含12个demo案例,学自b站狂神。希望可以帮助到小狂神们,同时也给自己的笔记收藏纪念一下
  • Java 注解和反射详解

    千次阅读 多人点赞 2020-09-15 09:09:28
    内置注解元注解@Target@Retention@Documented@Inherited自定义注解反射静态语言 VS 动态语言动态语言静态语言Java 反射机制概述Java 反射机制提供的功能Java 反射优点缺点反射相关的主要 API理解 Class 类并获取 ...

    注解

    什么是注解?

    • Annotation 是从 JDK 1.5 开始引入的新技术
    • Annotation 的作用
      • 不是程序本身,可以对程序作出解释(这一点和注释没什么区别)
      • 可以被其它程序(比如:编译器等)读取
    • Annotation 的格式
      • 注解是以 “@注释名” 在代码中存在的,还可以添加一些参数值,例如: @SuppressWarnings(value=“unchecked”)
    • Annotation 在哪里使用?
      • 可以附加在 package,class,method,field 等上面,相当于给他们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问

    如:(重写父类方法的时候会有个 @Override 注解)
    在这里插入图片描述

    内置注解

    • @Override:定义在 java.lang.Override 中,此注解只适用于修辞方法,表示一个方法声明打算重写超类中的另一个方法声明
    @Target(value=METHOD)
    @Retention(value=SOURCE)
    public @interface Override
    
    • @Deprecated:定义在 java.lang.Deprecated 中,此注释可以用于修辞方法,属性,类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择
    @Documented
    @Retention(value=RUNTIME)
    @Target(value={CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER,TYPE})
    public @interface Deprecated
    
    • @SuppressWarnings:定义在 java.lang.SuppressWarings 中,用来抑制编译时的警告信息,与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数都是已经定义好了的,我们选择性的使用就好了
      • @SuppressWarnings(“all”)
      • @SuppressWarnings(“unchecked”)
      • @SuppressWarnings(value={“unchecked”,“deprecation”})
      • 等等…
    @Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
    @Retention(value=SOURCE)
    public @interface SuppressWarnings
    

    元注解

    • 元注解的作用就是负责注解其它注解,Java 定义了 4 个标准的 meta-annotation 类型,它们被用来提供对其它注解类型做说明
    • 这些类型和它们所支持的类在 java.lang.annotation 包中可以找到(@Target,@Retention,@Documented,@Inherited)

    @Target

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

    如:我们自定义一个注解
    在这里插入图片描述
    ElementType 是一个枚举类,该类中提供了一些简单的分类(以下是该类的部分截图)
    在这里插入图片描述
    然后我们使用该注解

    public class Test01 {
        @MyAnnotation
        public void test() {
    
        }
    }
    

    在 @MyAnnotation 中还定义了可以在类中使用,所以也可以在类上面使用该注解,如:
    在这里插入图片描述

    @Retention

    表示需要在什么级别保存该注释信息,用于描述注解的生命周期(SOURCE < CLASS < RUNTIME
    在这里插入图片描述

    @Documented

    说明该注解将被包含在 javadoc 中
    在这里插入图片描述

    @Inherited

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

    在这里插入图片描述

    自定义注解

    • 使用 @interface 自定义注解时,自动继承了 java.lang.annotation.Annotation 接口
    • 分析:
      • @interface 用来声明一个注解,格式:public @interface 注解名 {定义内容}
      • 其中的每一个方法实际上是声明了一个配置参数
      • 方法的名称就是参数的名称
      • 返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)
      • 可以通过 default 来声明参数的默认值
      • 如果只有一个参数成员,一般参数名为 value
      • 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0 作为默认值
    import java.lang.annotation.*;
    
    /**
     * @author Woo_home
     * @create by 2020/8/1  20:12
     */
    public class Test01 {
    
        // 注解可以显示赋值,如果没有默认值,我们就必须给注解赋值
        @MyAnnotation(age = 18, name = "lisa")
        public void test() {
    
        }
        
        @DemoAnnotation("注解测试")
        public void test1() {
    
        }
    }
    
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @interface MyAnnotation {
        // 注解的参数:参数类型 + 参数名()
        String name() default "";
    
        int age();
    
        // 如果默认值为 -1,代表不存在
        int id() default -1;
    
        String[] schools() default {"大学"};
    }
    
    @Target({ElementType.TYPE, ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @interface DemoAnnotation {
        String value();
    }
    

    反射

    静态语言 VS 动态语言

    动态语言

    动态语言是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其它结构上的变化。通俗一点说就是在运行时代码可以根据某些条件改变自身结构

    静态语言

    与动态语言相对应,运行时结构不可变的语言就是静态语言,如 Java、C、C++

    Java 不是静态语言,但是 Java 可以称之为 “准动态语言”。即 Java 有一定的动态性,我们可以利用反射机制获得类似动态语言的特性。Java 的动态性让编程的时候更加灵活

    Java 反射机制概述

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

    Class c = Class.forName("java.lang.String");
    

        加载完类之后,在堆内存的方法区中就产生了一个 Class 类型的对象(一个类只有一个 Class 对象),这个对象就包含了完整类的类的结构信息。我们可以通过对这个对象看到的类的结构。这个对象就像一面镜子,通过这个镜子看到类的结构,所以,我们形象地称之为:反射

    • 正常方式:引入需要的 “ 包类 ” 名称 ——> 通过 new 实例化 ——> 取得实例化对象
    • 反射方式:实例化对象 ——> getClass() 方法 ——> 得到完整的 “包类” 名称

    Java 反射机制提供的功能

    • 在运行时判断任意一个对象所属的类
    • 在运行时构造任意一个类的对象
    • 在运行时判断任意一个类所具有的成员变量和方法
    • 在运行时获取泛型信息
    • 在运行时调用任意一个对象的成员变量和方法
    • 在运行时处理注解
    • 生成动态代理

    Java 反射优点和缺点

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

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

    反射相关的主要 API

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

    理解 Class 类并获取 Class 实例

    先定义一个实体类

    // 定义一个实体类
    public class User {
    
        private int id;
    
        private String name;
    
        private int age;
    
        public User() {
        }
    
        public User(int id, String name, int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    

    主程序

    package com.java.demo.reflect;
    
    /**
     * @author Woo_home
     * @create by 2020/8/1  20:12
     */
    public class Test01 {
        public static void main(String[] args) throws Exception {
            // 通过反射获取类的 Class 对象
            Class<?> aClass = Class.forName("com.java.demo.reflect.User");
            System.out.println(aClass);
        }
    }
    

    输出:
    在这里插入图片描述
    一个类在内存中只有一个 Class 对象,一个类被加载之后,类的整个结构都会被封装在 Class 对象中

    Class 类

    在 Object 类中定义了以下方法,此方法将被所有子类继承

    public final native Class<?> getClass();
    

    上面的方法返回值的类型是一个 Class 类,此类是 Java 反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称

    对于每个类而言,JRE 都为其保留了一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个结构(class / interface / enum / annotation / primitive type/void / [])

    • Class 本身也是一个类
    • Class 对象只能由系统建立对象
    • 一个加载的类在 JVM 中只会有一个 Class 实例
    • 一个 Class 对象对应的是一个加载到 JVM 中的一个 .class 文件
    • 每个类的实例都会记得自己是由哪个 Class 实例所生成
    • 通过 Class 可以完整地得到一个类中的所有被加载的结构
    • Class 类是 Reflection 的根源,针对任何你想动态加载、运行的类、唯有先获得响应的 Class 对象
    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 getMethod(String name, Class… T)返回一个 Method 对象,此对象的形参类型为 paramType
    Field[] getDeclaredFields()返回 Field 对象的一个数组

    获取 Class 类的实例

    public class Test01 {
        public static void main(String[] args) throws Exception {
            // 方式一:forName 获得
            Class aClass = Class.forName("com.java.demo.reflect.User");
            System.out.println(aClass);
    
            // 方式二:通过对象获得
            Class aClass1 = new User().getClass();
            System.out.println(aClass1);
    
            // 方式三:通过类名.class 获得
            Class<User> aClass2 = User.class;
            System.out.println(aClass2);
        }
    }
    

    所有类型的 Class 对象

    public class Test01 {
        public static void main(String[] args) {
            Class objectClass = Object.class;            // 类
            Class comparableClass = Comparable.class;    // 接口
            Class aClass = String[].class;               // 一维数组
            Class aClass1 = int[][].class;               // 二维数组
            Class overrideClass = Override.class;        // 注解
            Class elementTypeClass = ElementType.class;  // 枚举
            Class integerClass = Integer.class;          // 基本数据类型
            Class voidClass = void.class;                // void
            Class classClass = Class.class;              // Class
    
            System.out.println(objectClass);
            System.out.println(comparableClass);
            System.out.println(aClass);
            System.out.println(aClass1);
            System.out.println(overrideClass);
            System.out.println(elementTypeClass);
            System.out.println(integerClass);
            System.out.println(voidClass);
            System.out.println(classClass);
        }
    }
    

    输出:
    在这里插入图片描述

    Java 内存分析

    在这里插入图片描述

    类的加载与 ClassLoader 的理解

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

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

      • 验证:确保加载的类信息符合 JVM 规范,没有安全方面的问题
      • 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配
      • 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
    • 初始化:

      • 执行类构造器< clint>() 方法的过程,类构造器< clint>() 方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的(类构造器是构造类信息的,不是构造该类对象的构造器)
      • 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化
      • 虚拟机会保证一个类的< clint>() 方法在多线程环境中被正确加锁和同步
    package com.java.demo.reflect;
    
    /**
     * @author Woo_home
     * @create by 2020/8/1  20:12
     */
    public class Test01 {
        public static void main(String[] args) {
            /**
             * 1、加载到内存,会产生一个类对应的 Class 对象
             * 2、链接,链接结束后 m = 0
             * 3、初始化
                  <clint>() {
                        System.out.println("A 类静态代码块初始化");
                        m = 300;
                        m = 100;
                    }
                    m = 100;
             */
            A a = new A();
            System.out.println(A.m);
        }
    }
    
    class A {
        static {
            System.out.println("A 类静态代码块初始化");
            m = 300;
        }
    
        static int m = 100;
    
        public A() {
            System.out.println("A 类的无参构造函数初始化");
        }
    }
    

    输出:
    在这里插入图片描述

    获取运行时类的完整结构 & 动态创建对象执行方法

    Field、Method、Constructor、SuperClass、Interface、Annotation

    • 实现的全部接口
    • 所继承的父类
    • 全部的构造器
    • 全部的方法
    • 全部的 Field
    • 注解

    具体可以看下之前写的这篇文章,写得很详细 Java反射机制的简单使用

    性能对比分析

    setAccessible

    • Method 和 Field、Constructor 对象都有 setAccessible() 方法
    • setAccessible 作用是启动和禁用访问安全检查的开关
    • 参数值为 true 则提示反射的对象在使用时应该取消 Java 语言访问检查
      • 提高反射的效率,如果代码中必须用反射,而该语句需要频繁的被调用,那么请设置为 true
      • 使得原本无法访问的私有成员也可以访问
    • 参数值为 false 则指示反射的对象应该实施 Java 语言访问检查
    package com.java.demo.reflect;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    /**
     * @author Woo_home
     * @create by 2020/8/1  20:12
     */
    public class Test01 {
    
        // 普通方式调用
        public static void test01() {
            User user = new User();
            long startTime = System.currentTimeMillis();
            for (int i = 0; i < 100000000; i++) {
                user.getName();
            }
            long endTime = System.currentTimeMillis();
            System.out.println("普通方式执行 1 亿次:" + (endTime - startTime) + "ms");
        }
    
        // 反射方式调用
        public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            User user = new User();
            Class c = user.getClass();
            Method getName = c.getDeclaredMethod("getName", null);
            long startTime = System.currentTimeMillis();
            for (int i = 0; i < 100000000; i++) {
                getName.invoke(user, null);
            }
            long endTime = System.currentTimeMillis();
            System.out.println("反射方式执行 1 亿次:" + (endTime - startTime) + "ms");
        }
    
        // 反射方式调用,关闭检测
        public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            User user = new User();
            Class c = user.getClass();
            Method getName = c.getDeclaredMethod("getName", null);
            getName.setAccessible(true);
            long startTime = System.currentTimeMillis();
            for (int i = 0; i < 100000000; i++) {
                getName.invoke(user, null);
            }
            long endTime = System.currentTimeMillis();
            System.out.println("关闭检测方式执行 1 亿次:" + (endTime - startTime) + "ms");
        }
    
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
            test01();
            test02();
            test03();
        }
    }
    

    输出:
    在这里插入图片描述

    通过输出结果可以发现,普通方式执行是最快的,其次就是关闭检测的方式

    通过反射去操作泛型

    • Java 采用泛型擦除的机制来引入泛型,Java 中的泛型仅仅是给编译器 javac 使用的,确保数据的安全性和免去强制类型转换问题,但是,一旦编译完成,所有和泛型有关的类型全部擦除
    • 为了通过反射操作这些类型,Java 新增了 ParameterizedType,GenericArrayType,TypeVariable 和 WildcardType 几种类型来代表不能被归一到 Class 类中的类型但是又和原始类型齐名的类型
      • ParameterizedType:表示一种参数化类型,比如 Collection< String>
      • GenericArrayType:表示一种元素类型时参数化类型或者类型变量的数组类型
      • TypeVariable :是各种类型变量的公共父接口
      • WildcardType :代表一种通配符类型表达式
    package com.java.demo.reflect;
    
    import java.lang.reflect.Method;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @author Woo_home
     * @create by 2020/8/1  20:12
     */
    public class Test01 {
    
        public void test01(Map<String, User> map, List<User> list) {
            System.out.println("test01");
        }
    
        public Map<String, User> test02() {
            System.out.println("test02");
            return null;
        }
    
        // 通过反射获取泛型
        public static void main(String[] args) throws NoSuchMethodException {
            Method test01 = Test01.class.getMethod("test01", Map.class, List.class);
            // 获取通用参数类型
            Type[] genericParameterTypes = test01.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);
                    }
                }
            }
    
            Method test02 = Test01.class.getMethod("test02", null);
            Type genericReturnType = test02.getGenericReturnType();
            if (genericReturnType instanceof ParameterizedType) {
                Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }
    }
    

    输出:
    在这里插入图片描述

    反射操作注解

    • getAnnotations
    • getAnnotation

    先定义两个注解,待会儿会用到

    // 类名注解
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Tables {
        String value();
    }
    
    // 属性的注解
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Fields {
        String columnName();
        String type();
        int length();
    }
    

    然后我们在实体类中使用我们定义的注解(是不是跟 JPA 有点像?)

    @Tables("db_student")
    public class Student {
    
        @Fields(columnName = "db_id", type = "int", length = 10)
        private int id;
    
        @Fields(columnName = "db_age", type = "int", length = 10)
        private int age;
    
        @Fields(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) {
            this.id = id;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "id=" + id +
                    ", age=" + age +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    

    然后反射来获取注解信息

    public class Test01 {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
            Class c1 = Class.forName("com.java.demo.reflect.Student");
    
            // 通过反射获得注解
            Annotation[] annotations = c1.getAnnotations();
            for (Annotation annotation : annotations) {
                System.out.println(annotation);
            }
    
            // 获得注解的 value 值
            Tables tables = (Tables) c1.getAnnotation(Tables.class);
            String value = tables.value();
            System.out.println(value);
    
            // 获得类指定的注解
            Field field = c1.getDeclaredField("name");
            Fields annotation = field.getAnnotation(Fields.class);
            System.out.println(annotation.columnName());
            System.out.println(annotation.type());
            System.out.println(annotation.length());
        }
    }
    

    输出:
    在这里插入图片描述

    扩展

    自定义注解的场景及实现

        登陆、权限拦截、日志处理,以及各种 Java 框架,如 Spring,Hibernate,Junit 提到注解就不能不说到反射,Java 自定义注解是通过运行时靠反射获取注解。

        实际开发中,例如我们要获取某个方法的调用日志,可以通过 AOP(动态代理机制)给方法添加切面,通过反射来获取方法包含的注解,如果包含日志注解,就进行日志记|录

    展开全文
  • 重点: Javadoc 不同,Java 标注可以通过反射获取标注内容。 大话空话不用说太多,简而言之,在编译器生成类文件时,标注 可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 ...

    前言

    Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。
    重点:和 Javadoc 不同,Java 标注可以通过反射获取标注内容。
    大话空话不用说太多,简而言之,在编译器生成类文件时,标注 可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。
    反射+注解,是不是感觉Java变成一种动态语言?哈哈哈!

    我觉得注解可以分为三个部分来讲:内置注解,元注解,自定义注解。

    一、内置注解

    1、@Override 重写

    概念:检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。

    //这个extends 不要在意,我写上去只是为了更加方便直观的去理解,Object是万物之源,不写也会默认是其子类,不用解释过多吧?
    public class Annotation1 extends Object{
    
        @Override
        public String toString (){
            return "我是重新定义过的toString方法";
        }
    }
    

    @Override(重写),这个大家应该很熟悉,重写父类的方法。
    我们可以看下Object类中toString()是什么样子的。
    在这里插入图片描述
    那么显而易见,使用了@Override(重写)注解,方法名、方法参数必须得和父类保持一致,否则会报错。
    如下图所示:
    在这里插入图片描述
    如果不加@Override(重写)注解,则正常编译。
    在这里插入图片描述

    2、@Deprecated 过期警告

    概念:标记过时方法。如果使用该方法,会报编译警告。
    在开发中,我们经常能遇到这样的情况,如下图:
    在这里插入图片描述
    在jdk中有大量这样的方法,我就不举例了,自己写一个可能会更加方便理解。

    public class Annotation1 extends Object{
        public static void main(String[] args) {
            testDeprecated.toString1();
        }
    }
    class testDeprecated {
        @Deprecated
        public static String toString1(){
            return "我是重新定义过的toString方法";
        }
    }
    

    在这里插入图片描述

    注意点: 这个不是报错,只是警告,提醒我们这个方法可能会有问题,可能有更好的方法来实现!

    3、@SuppressWarnings 忽略警告

    概念:指示编译器去忽略注解中声明的警告。

    平时开发中,我们会遇到这样的情况,如下图:
    在这里插入图片描述
    这也不是错误,这是提醒我们,该方法没有使用到,警告提醒的作用。
    加上@SuppressWarnings注解后。

    public class Annotation1 extends Object{
        public static void main(String[] args) {
    
        }
        @SuppressWarnings("all")
        public static void testSuppressWarnings(){
            System.out.println("测试+testSuppressWarnings忽略警告!");
        }
    }
    

    方法成功高亮起来,并且没有警告提示了!
    在这里插入图片描述
    我们可以点进去看下这个注解为什么需要参数?
    在这里插入图片描述
    看这里,这个不是方法哦,这是参数。
    在注解中的参数格式:calss + 参数名 + ()
    这个需要强行记忆哦,回头我们自定义注解时也需要用到。
    换一种写法加深理解!如下图:
    在这里插入图片描述
    注意点:当注解中只有一个参数时,我们无需加上参数名,注解会自动帮我们匹配的。
    具体参数参考点击这里哦

    二、元注解

    概念:顾名思义,元注解就是给注解使用的注解!

    1、@Retention 作用域-(常用)

    概念:表示在什么级别保存该注解信息。
    在实际开发中,我们一般都写RUNTIME,除非项目有特殊需求!
    我们看下@Retention的源码。
    在这里插入图片描述
    可以看到,需要一个参数,进参数瞅瞅。
    在这里插入图片描述
    SOURCE: 源代码时有用。
    CLASS: class文件中有用,但会被jvm丢弃。
    RUNTIME: 运行时有用。
    关系:RUNTIME>CLASS>SOURCE

    后面我们自定义注解时,每个都需要用该注解!

    2、@Documented 作用文档

    概念:将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。
    老规矩看下源码:
    在这里插入图片描述
    无参的注解,作用域为RetentionPolicy.RUNTIME,运行时有用!这个只是用来作为标记,了解即可,在实际运行后会将该注解写入javadoc中,方便查看。

    3、@Target 目标-(常用)

    概念: 标记这个注解应该是使用在哪种 Java 成员上面!
    在这里插入图片描述
    参数源码:
    在这里插入图片描述
    注意这里时数组格式的参数,证明可以传多个值。
    @Target(ElementType.TYPE)——接口、类、枚举、注解
    @Target(ElementType.FIELD)——字段、枚举的常量
    @Target(ElementType.METHOD)——方法
    @Target(ElementType.PARAMETER)——方法参数
    @Target(ElementType.CONSTRUCTOR) ——构造函数
    @Target(ElementType.LOCAL_VARIABLE)——局部变量
    @Target(ElementType.ANNOTATION_TYPE)——注解
    @Target(ElementType.PACKAGE)——包

    我们来试一下:
    在这里插入图片描述
    目标不对会报错的哦!我们将其改成方法上!编译即正常通过。
    在这里插入图片描述
    其他的作用域大家可以去自行尝试,篇幅问题,无法做到每个都去试一遍!

    4、@Inherited 继承

    概念:标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)。
    在这里插入图片描述
    这个很简单,就是当@InheritedAnno注解加在某个类A上时,假如类B继承了A,则B也会带上该注解。

    4、新注解-(了解即可)

    从 Java 7 开始,额外添加了 3 个注解:

    @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
    @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
    @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

    三、自定义注解

    我们来定义一个属于自己的注解。

    @Retention(value = RetentionPolicy.RUNTIME)
    @Target(value = ElementType.METHOD)
    @Inherited
    @interface myAnnotation {
        String name() default "";
        int age() default 18;
        String like();
        String IDCard() default "";
    }
    

    格式:修饰符(pulic)+ @interface +注解名+ {参数等}
    可利用default 设置默认值,设定了默认值后使用注解时不传值也不会报错,反之报错!
    在这里插入图片描述
    我们只需要传没有默认值的参数即可。
    如果不传则报错:
    在这里插入图片描述

    总结

    主要就是要注意元注解的使用,因为我们自定义注解时必须得用到!
    其实注解主要配合反射来用,在此就不展开来叙述了,下一篇文章讲解反射时,会结合注解详细讲解!

    在这里插入图片描述
    Java注解和反射扩展:Java注解和反射学习汇总

    路漫漫其修远兮,吾必将上下求索~
    如果你认为i博主写的不错!写作不易,请点赞、关注、评论给博主一个鼓励吧**转载请注明出处哦**

    展开全文
  • JAVA 注解和反射.7z

    2021-04-08 12:45:34
    JAVA 注解和反射.7z
  • 一个非常简单的 Java 注释和反射示例。 对任何开始熟悉这些概念的人都有用。
  • 主要介绍了Java使用注解和反射简化编程的方法,结合实例形式分析了java使用注解和反射调用大量函数简化编程的相关操作技巧,需要的朋友可以参考下
  • Java注解和反射

    千次阅读 热门讨论 2021-03-01 15:10:19
    一、注解 注解(Annotation): 从jdk5.0开始引进,可以对程序进行解释或被其他程序读取。 注解格式:"@注释名",并可以添加一些参数。 例:@MyAnnotation(value=‘value’) 1、内置注解 @override: 用于修饰方法,...

    一、注解

    注解(Annotation): 从jdk5.0开始引进,可以对程序进行解释或被其他程序读取。

    注解格式:"@注释名",并可以添加一些参数。
    例:@MyAnnotation(value=‘value’)

    1、内置注解

    @override: 用于修饰方法,表示该方法声明是重写或实现一个父类的方法

    @Deprecated: 用于修饰方法、属性、类,表示已过时不建议使用的

    @SuppressWarnings: 用于抑制编译时的警告信息

    2、元注解

    作用:用于注解其他注解

    @Target: 用于描述注解的适用范围
    例:@Target(ElementType.ANNOTATION_TYPE) 适用范围为注解定义

    @retention: 表示需要在什么级别保存该注解信息
    SOURCE - 源码级别
    CLASS - class级别
    RUNTIME - 运行级别
    SOURCE < CLASS < RUNTIME
    例:@Retention(RetentionPolicy.RUNTIME) 此注解运行时有效

    @Documented: 表示是否将注解生成在Javadoc中

    @Inherited: 表示子类可以继承父类的注解

    3、自定义注解

    注解定义:@interface+注解名

    @Target(ElementType.METHOD)//作用在方法上
    @Retention(RetentionPolicy.RUNTIME)//运行时有效
    @interface Myannotation1{
        //注解的参数:参数类型 + 参数名();
        String Parameter1() ;
        int Parameter2() default -1; //默认值为-1代表不存在
    }
    
    @Target(ElementType.METHOD)//作用在方法上
    @Retention(RetentionPolicy.SOURCE )//源码中有效
    @interface Myannotation2{
        String Value() ;//只有一个参数时,参数名用Value
    }
    

    测试:

        //有默认值的参数可以不填没有默认值的参数必填,并且参数填写没有顺序
        @Myannotation1(Parameter1 = "Parameter1 ")
        //参数定义为Value时,前面的"Value = "可以省略
        @Myannotation2("Value")
        public void test01(){
    
        }
    

    二、反射

    反射(Reflection)是java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
    优缺点:具有灵活性但是效率较低。

    Class c = Class.forName(java.lang.String)

    1、Class类

    某个类的属性、方法和构造器、某个类实现了哪些接口,JRE都为其保留了一个不变的Class类型的对象,同一个类的所有对象共享同一个Class对象。
    Class类具有以下特点:

    • Class本身也是一个类
    • Class对象只能由系统建立对象
    • 一个加载的类在JVM中只会有一个Class实例
    • 一个Class对象对应的是一个加载到JVM中的一个class文件
    • 每个类的实例都会记得自己是由哪个Class实例所生成
    • 通过Class可以完整地得到一个类中的所有被加载结构
    • Class类是Reflection的根源,针对任何想动态加载、运行的类,唯有先获得相应的Class对象

    Class类的常用方法:

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

    2、通过反射获取Class对象:

    所有的类都可以通过反射获取其Class对象。
    下面通过例子列举获取类的Class对象的三种方式:

    //新建Person类
    class Person{
    	String name;
    	int age;
    	int id;
    
        public Person() {
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    
    //测试
    public class test02 {
    
        public static void main(String[] args) throws ClassNotFoundException {
            Person person = new Person();
            //方式一、通过包名获取
    		Class class1 = Class.forName("com.reflection.Person");
    		System.out.println(class1.hashCode());
    		//方式二、通过对象获取
    		Class class2 = person.getClass();
    		System.out.println(class3.hashCode());
    		//方式三、通过类获取
    		Class class3 = Person.class;
    		System.out.println(class3.hashCode());
    	}
    }
    

    输出结果:
    在这里插入图片描述
    结论:三种方式获取的Class对象为同一个。

    3、获取类的运行时结构

    public class test03 {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
            Class c1 = Class.forName("com.reflection.Person");
            //获得类的名字
            String name = c1.getName();//获得包名加类名
            String simpleName = c1.getSimpleName();//获得类名
    
            //获得类的属性
            Field[] fields = c1.getFields();//获得类的所有公有属性
            Field[] declaredFields = c1.getDeclaredFields();//获得类的所有属性
            Field field = c1.getField(name);//获得类的指定公有属性
            Field declaredField = c1.getDeclaredField(name);//获得类的指定属性(所有类型均可)
            
            //获得类的方法
            Method[] method = c1.getMethods();//获得本类及其父类的所有公有方法
            Method[] declaredMethods = c1.getDeclaredMethods();//获得本类的所有方法
            Method getName = c1.getMethod("getName", null);//获取指定方法(本类及其父类的所有公有方法)
            Method setName = c1.getDeclaredMethod("setName", String.class);//获取指定方法(本类的所有方法)
    
            //获得类的构造器
            Constructor[] constructors = c1.getConstructors();//获取所有公有构造器
            Constructor[] declaredConstructors = c1.getDeclaredConstructors();//获取所有构造器
            Constructor constructor = c1.getConstructor(String.class, int.class);//获取指定公有构造器
            Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class);//获取指定构造器
    
        }
    }
    
    

    4、通过反射构造对象

    public class Test04 {
        public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
            //获得Class对象
            Class c1 = Class.forName("com.reflection.Person");
            //通过反射创建对象
            Person person = (Person)c1.newInstance();//本质上是调用了无参构造器
    
            Constructor constructor = c1.getDeclaredConstructor(String.class,int.class);//获取有参构造器
            Person person2 = (Person) constructor.newInstance("name",18);//调用有参构造器创建对象
    
            //通过反射调用普通方法
            Method setName = c1.getDeclaredMethod("setName", String.class);//获取方法
            setName.invoke(person,"name");//通过invoke调用方法
    
            //通过反射操作属性
            Field name = c1.getDeclaredField("name");//获取name属性
            name.setAccessible(true);//关闭安全检测,关闭后可以访问私有属性(true为关闭,false为打开,默认是false)
            name.set(person,"lalala");//设置属性的值
    
        }
    }
    
    

    5、通过反射获取注解的信息

    创建类和注解

    @Testclass("db_Student2")//类注解
    //创建学生类
    class Student2{
        @Testfield(columnname = "name",type = "varchar",length = 20)//属性注解
        String name;
        @Testfield(columnname = "age",type = "int",length = 3)
        int age;
        @Testfield(columnname = "ID",type = "int",length = 10)
        int ID;
    
        public Student2() {
        }
    
        public Student2(String name, int age, int ID) {
    
            this.name = name;
            this.age = age;
            this.ID = ID;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public int getID() {
            return ID;
        }
    
        public void setID(int ID) {
            this.ID = ID;
        }
    }
    
    
    //类的注解
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Testclass{
        String value();
    }
    //属性的注解
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Testfield{
        String columnname();
        String type();
        int length();
    }
    

    测试

    public class test05 {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
            Class c1 = Class.forName("com.zjrcu.reflection.Student2");
    
            //通过反射获得注解
            Annotation[] annotations = c1.getAnnotations();
            for (Annotation annotation : annotations) {
                System.out.println(annotation);
            }
            
            //通过反射获得注解value的值
            Testclass testclass = (Testclass)c1.getAnnotation(Testclass.class);
            String value = testclass.value();
            System.out.println(value);
            
            //获取类中指定注解的value值
            Field f = c1.getDeclaredField("name");
            Testfield testfield = (Testfield) f.getAnnotation(Testfield.class);
            System.out.println(testfield.columnname());
            System.out.println(testfield.length());
            System.out.println(testfield.type());
    
    
        }
    }
    
    展开全文
  • 一种基于Java注解和反射机制的Excel文件读写操作方法
  • JAVA注解和反射

    2019-04-18 13:59:50
    JAVA注解 什么是注解 注解目前还是非常流行的,我们常用的Sprinng就是利用注解。 添加注解可以代码简洁,阅读方便 ,使用方便。 首先,先来看一下我们java自带的元注释,在java.lang.annotation包下面,其中@...
  • Java注解和反射(三)类加载过程

    万次阅读 2021-03-01 10:36:57
    学习了类加载过程,可以更加方便我们理解反射的机制原理。没兴趣的同学可直接跳过该篇。 一、类加载过程 1、加载(load) 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,...
  • 前面我们讲了反射对象的获取类的加载过程,接下来我们得讲下如何使用反射的class对象! 一、获取运行时类的结构 通过反射可以获取运行时类的完整结构: ①FIeld(属性) ②Method(方法) ③Constructor(构造器)...
  • 一文掌握Java注解和反射-你总该用过@Override吧?

    千次阅读 多人点赞 2021-03-19 10:41:08
    注解不是程序本身,可以对程序作出解释说明(这一点注释(comment)没什么区别)。 反射(Reflection)机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。 双亲...
  • java注解反射的基本使用(这一篇就够了!)

    千次阅读 多人点赞 2020-03-28 16:42:06
    一、注解(Annotation) 1.什么是注解? 相信大家对注解应该并不陌生,在现在信息飞速发展的年代,各种优秀的框架或许都离不开注解的使用,像我们在实现接口一个方法时,也会有@Override注解注解说白了就是对对...
  • java注解和反射的应用

    千次阅读 2019-07-19 17:22:17
    注解和反射经常结合在一起使用,在很多框架的代码中都能看到他们结合使用的影子 所以要想成为一个架构师,想要编写自己的框架,一定要能熟练的使用注解和反射注解的概念 注解在我看来就是一个标签,用来标记所...
  • 注释一样,注解不是程序本身,而是对程序作出解释,而注解与注释不同的点在于,注解可以被其他程序比如编译器读取 @Override//重写注解 @Deprecated//不推荐使用注解,可以使用但是又风险或者有更好的方式 @...
  • 【狂神说Java注解和反射---文档第1集:什么是注解一、注解概念第2集:内置注解一、内置注解第3集:什么是元注解一、元注解第4集:自定义注解一、自定义注解 第1集:什么是注解 (注意:点我看视频) 一、注解概念 ...
  • 简单demo,导入即可运行。
  • Java注解和反射(二)Calss对象

    万次阅读 2021-02-24 11:39:54
    Java让我们在运行时识别对象类的信息,主要有2种方式:一种是传统的RTTI,它假定我们在编译时已经知道了所有的类型信息;另一种是反射机制,它允许我们在运行时发现使用类的信息。 二、反射的对象 1、通过类来...
  • Java注解和反射学习汇总(已完结)

    万次阅读 2021-02-25 16:19:13
    Java注解和反射(一)注解的学习理解 Java注解和反射(二)Calss对象 . . 未完待续!!!!! 写作不易,如果您觉得写的不错,欢迎给博主点赞、收藏、评论、收藏来一波~让博主更有动力吧! 路漫漫其修远兮,吾...
  • 关于Java你不知道的那些事之Java注解和反射

    千次阅读 多人点赞 2020-10-12 13:47:04
    Java注解和反射前言什么是注解内置注解元注解自定义注解反射机制动态语言与静态语言动态语言静态语言Java反射机制概述什么是反射反射的应用Java反射的优缺点反射相关的主要API理解Class类并获取Class实例Class类...
  • 利用JAVA注解实现SQL语句自动生成 编写对应Entity添加相关注解,并通过SqlUtil工具,传入相关参数生成SQL语句 例如:要生成对应数据库Person的SQL增删改查 SqlUtil.create(Person.class) SqlUtil.insert(Person....
  • java泛型反射注解

    2016-08-18 16:34:46
    先说一下遇到的问题:通过使用GSON泛型进行报文转换的时候想要对部分关键字段加密,...解决过程:首先通过反射获取到bean下的对象名称。 对象名称获取到了之后需要获取对应的值 对值进行加密,然后再重新赋值到该对象
  • 今天小编就为大家分享一篇关于Java注解反射原理说明,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
  • JAVA注解和反射(笔记)

    万次阅读 2020-12-24 14:05:18
    不是程序本身(可以对程序作出解释.(这一点注释(comment)没什么区别) 可以被其他程序(比如:编译器等)读取. Annotation的格式: 注解是以"@注释名"在代码中存在的, 还可以添加一些参数值,例如:@SuppressWarnings...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 116,146
精华内容 46,458
关键字:

java注解和反射

java 订阅