• 面试题


    annotation

    什么是注解

    • Annotation是从JDK5.0开始引入的新技术。

    • Annotation的作用:

      • 不是程序本身,可以对程序作出解释。(这一点,跟注释没什么区别)
      • 可以被其他程序(比如:编译器等)读取。(注解信息处理流程,是注解和注释的重大区别 。如果没有注解信息处理流程,则注解毫无意义)
    • Annotation的格式:

      • 注解是以“@注释名”在代码中存在的,还可以添加一些参数值,例如: @SuppressWarnings(value="unchecked")。
    • Annotation在哪里使用?

      • 可以附加在package, class, method, field等上面,相当于给它们添加了额外的辅助信 息,我们可以通过反射机制编程实现对这些元数据的访问。

    JDK内置了哪些注解?

    1. Overried
      Overried是告诉编译器要检查该方法是实现父类的方法。
    2. Deprecated
      Deprecated用于标记一些过时的代码。
    3. SuppressWarnings
      SuppressWarnings用于消除一些警告信息,使用集合的时候,如果没有指定泛型,IDE会提示安全检查的警告。
    4. FunctionalInterface
      FunctionalInterface是JDK8中的注解,用来指定该接口是函数式接口。
    5. SafeVarargs
      SafeVarargs是JDK 7中的注解,主要目的是处理可变长参数中的泛型,此注解告诉编译器:在可变长参数中的泛型是类型安全的。

    元注解【生命周期、作用域】

    1. Target
      用于指定被修饰的注解修饰哪些程序单元,也就是上面说的类,方法,字段

    2. Retention
      用于指定被修饰的注解被保留多长时间,分别

      • SOURCE(注解仅存在于源码中,在class字节码文件中不包含)
      • CLASS(默认的保留策略,注解会在class字节码文件中存在,但运行时无法获取)
      • RUNTIME(注解会在class字节码文件中存在,在运行时可以通过反射获取到)

      三种类型,如果想要在程序运行过程中通过反射来获取注解的信息需要将Retention设置为RUNTIME

    3. Documented
      用于指定被修饰的注解类将被javadoc工具提取成文档

    4. Inherited
      用于指定被修饰的注解类将具有继承性

    注解的使用场景?

    • 编译器的信息

      使用注解,编译器可以检测错误或抑制警告

    • 生成文档
      Swagger中就是通过注解对接口,实体类中的字段进行描述生成可视化的文档

    • 代替配置文件
      Spring中Bean的装载注入

    • 导出数据
      可以写一个统一的导出工具类,传入一个List<实体类>进去即可导出Excel文件,Excel的表头可以用注解加载字段上

    • 框架层面的统一处理
      注解在底层框架中用的比较多,在框架中需要考虑到通用性,能用注解做很多事情,比如对API进行权限控制,限流等操作都可以通过自定义注解来标识是否需要进行认证,限流等,还有数据的缓存,典型的就是@Cacheable,还有异步方法的调用@Async,ORM框架中的使用,可以用注解标识表名,字段名,JPA中,Spring Data框架中都有使用

    可以从注解方法声明返回哪些对象类型?

    返回类型必须是基本类型,StringClassEnum数组类型之一。否则,编译器将抛出错误。

    这是一个成功遵循此原则的示例代码:

    enum Complexity {
        LOW, HIGH
    }
    
    public @interface ComplexAnnotation {
        Class<? extends Object> value();
    
        int[] types();
    
        Complexity complexity();
    }
    

    下一个示例将无法编译,因为Object不是有效的返回类型:

    public @interface FailingAnnotation {
        Object complexity();
    }
    

    哪些程序元素可以注解?

    注解可以应用于整个源代码的多个位置。它们可以应用于类,构造函数和字段的声明:

    @SimpleAnnotation
    public class Apply {
        @SimpleAnnotation
        private String aField;
    
        @SimpleAnnotation
        public Apply() {
            // ...
        }
    }
    

    方法及其参数:

    @SimpleAnnotation
    public void aMethod(@SimpleAnnotation String param) {
        // ...
    }
    

    局部变量,包括循环和资源变量:

    @SimpleAnnotation
    int i = 10;
    
    for (@SimpleAnnotation int j = 0; j < i; j++) {
        // ...
    }
    
    try (@SimpleAnnotation FileWriter writer = getWriter()) {
        // ...
    } catch (Exception ex) {
        // ...
    }
    

    其他注解类型:

    @SimpleAnnotation
    public @interface ComplexAnnotation {
        // ...
    }
    

    甚至包,通过package-info.java文件:

    @PackageAnnotation
    package com.baeldung.interview.annotations;
    

    从Java 8开始,它们也可以应用于类型的使用。为此,注解必须指定值为ElementType.USE的@Target注解:

    @Target(ElementType.TYPE_USE)
    public @interface SimpleAnnotation {
        // ...
    }
    

    现在,注解可以应用于类实例创建:

    new @SimpleAnnotation Apply();
    

    类型转换:

    aString = (@SimpleAnnotation String) something;
    

    接口中:

    public class SimpleList<T>
      implements @SimpleAnnotation List<@SimpleAnnotation T> {
        // ...
    }
    

    抛出异常上:

    void aMethod() throws @SimpleAnnotation Exception {
        // ...
    }
    

    有没有办法限制可以应用注解的元素?

    有,@ Target注解可用于此目的。如果我们尝试在不适用的上下文中使用注解,编译器将发出错误。

    以下是仅将@SimpleAnnotation批注的用法限制为字段声明的示例:

    @Target(ElementType.FIELD)
    public @interface SimpleAnnotation {
        // ...
    }
    

    如果我们想让它适用于更多的上下文,我们可以传递多个常量:

    @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PACKAGE })
    

    我们甚至可以制作一个注解,因此它不能用于注解任何东西。当声明的类型仅用作复杂注解中的成员类型时,这可能会派上用场:

    @Target({})
    public @interface NoTargetAnnotation {
        // ...
    }
    

    是否可以扩展注解?

    注解总是扩展java.lang.annotation.Annotation,如Java语言规范中所述。

    如果我们尝试在注解声明中使用extends子句,我们将得到一个编译错误:

    public @interface AnAnnotation extends OtherAnnotation {
        // Compilation error
    }
    

    什么是重复注解?

    这些是可以多次应用于同一元素声明的注解。

    出于兼容性原因,由于此功能是在Java 8中引入的,因此重复注解存储在由Java编译器自动生成的容器注解中。对于编译器来说,执行此操作有两个步骤。

    首先,我们需要声明一个可重复的注解:

    @Repeatable(Schedules.class)
    public @interface Schedule {
        String time() default "morning";
    }
    

    然后,我们使用强制值元素定义包含注解,其类型必须是可重复注解类型的数组:

    public @interface Schedules {
        Schedule[] value();
    }
    

    现在,我们可以多次使用@Schedule:

    @Schedule
    @Schedule(time = "afternoon")
    @Schedule(time = "night")
    void scheduledMethod() {
        // ...
    }
    

    你怎么能检索注解?这与保留政策有何关系?

    您可以使用Reflection API或注解处理器来检索注解。

    该@Retention注解和其的RetentionPolicy参数会影响您检索它们。RetentionPolicy枚举中有三个常量:

    • RetentionPolicy.SOURCE - 使注解被编译器丢弃,但注解处理器可以读取它们
    • RetentionPolicy.CLASS - 表示注解已添加到类文件中,但无法通过反射访问
    • RetentionPolicy.RUNTIME -Annotations由编译器记录在类文件中,并由JVM在运行时保留,以便可以反射性地读取它们

    以下是创建可在运行时读取的注解的示例代码:

    @Retention(RetentionPolicy.RUNTIME)
    public @interface Description {
        String value();
    }
    

    现在,可以通过反射检索注解:

    Description description
      = AnnotatedClass.class.getAnnotation(Description.class);
    System.out.println(description.value());
    

    注解处理器可以使用RetentionPolicy.SOURCE

    当您编写Java字节码解析器时,RetentionPolicy.CLASS可用。

    reflection

    什么是反射

    • 反射就是动态加载对象,并对对象进行剖析。
    • 在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
    • 对于任意一个对象,都能够调用它的任意一个方法,这种动态获取信息以及动态调用对象方法的功能成为Java反射机制。

    反射优缺点

    优点

    • 反射提高了程序的灵活性和扩展性,在底层框架中用的比较多,业务层面的开发过程中尽量少用。

    缺点

    • 性能不好
      • 反射是一种解释操作,用于字段和方法接入时要远慢于直接代码
  • 相关阅读:
    nginx
    git命令
    mysql的优化
    nginx下的负载均衡
    IO模式和IO多路复用
    回顾java基础—Java数据类型
    解决jdk1.8上编译dubbo失败
    KB,Kb单位换算,网络带宽中的Kbps和KB/s到底是什么意思? (注:B和b的区别)
    生成器函数_yield_yield from_send
    推导式_集合
  • 原文地址:https://www.cnblogs.com/sweetorangezzz/p/13096698.html
Copyright © 2020-2023  润新知