Java自定义属性转载

原创
小哥 3年前 (2022-10-28) 阅读数 208 #JAVA
文章标签 javajava教程

前言

随着springboot的受欢迎程度,以前是基于XML的spring配置越来越少,JavaConfig表格的使用越来越多,相似:

复制代码

@Configuration
public class AppConfig {    
    @Bean(name="helloBean")
    public HelloWorld helloWorld() {
        return new HelloWorldImpl();
    }   
}

可以看出,更多的是基于注释。(Annotation)已实现,包括springboot的入口类**Application。

复制代码

@Configuration
@ComponentScan("com.alibaba.trade")
@EnableAutoConfiguration//(exclude = {PageHelperAutoConfiguration.class})
@ServletComponentScan
@EnableTransactionManagement
@EnableDiscoveryClient
@EnableWebMvc
@MapperScan("com.alibaba.trade.shared.mapper")
public class TradeApplication extends SpringBootServletInitializer {
    public static void main(String[] args) {
        SpringApplication.run(TradeApplication.class, args);
    }
}

Java批注不仅允许我们减少XML文件,这便于维护,也使我们的代码更简洁。那么,我们如何在项目中读取批注并创建自己的批注呢?

注解说明

Java注解又称Java标注,是Java语言5.0该版本开始支持用于添加源代码的特殊语法元数据。它为我们提供了一种将信息添加到代码中的正式方法,以便我们可以在以后非常方便地使用数据。
Java可以标记该语言中的类、方法、变量、参数和包。和Javadoc不同,Java批注可以通过反射获取批注内容。当编译器生成类文件时,注释可以嵌入到字节码中。Java虚拟机可以在运行时保留注释内容并获取注释内容。

内置注解

Java 定义一组共享的注释 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。
1作用于代码的注释是

  • @Override - 检查该方法是否为重写方法。如果找到它的父类,或者如果引用的接口中没有这样的方法,则将报告编译错误。
  • @Deprecated - 标记过时的方法。如果使用此方法,将报告编译警告。
  • @SuppressWarnings - 指示编译器忽略批注中声明的警告。

2,在其他注释中的角色(或者说 元注解 )是:

  • @Retention - 确定此批注是如何保存的,是仅保存在代码中还是合并到代码中class文件,或者可以在运行时由反射访问。
  • @Documented - 标记这些备注是否包含在用户文档中。
  • @Target - 标记哪种批注应为 Java 成员。
  • @Inherited - 标记此批注从哪个批注类继承(默认 该批注不是从任何子类继承的。)

3、从 Java 7 首先,请添加其他 3 个注解:

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

元注解

1、 @Retention

@Retention annotation指定标记注释的存储方式:

  • RetentionPolicy.SOURCE - 标记的注释仅保留在源代码级别,并被编译器忽略。
  • RetentionPolicy.CLASS - 标记的评论编译器在编译时保留。Java虚拟机(JVM)将被忽略。
  • RetentionPolicy.RUNTIME - 标记的评论JVM保留,以便运行时环境可以使用它。

2、 @Documented

@Documented 注释指示无论何时使用指定的注释,都应使用该注释Javadoc用于记录这些元素的工具。(默认情况下,注释不包括在JavadocIn。)有关详细信息,请参阅 Javadoc工具页。

3、 @Target

@Target 备注标记另一个备注以限制可以应用的备注数量。Java元素类型。目标批注将以下元素类型之一指定为其值

  • ElementType.TYPE 可以应用于类的任何元素。
  • ElementType.FIELD 可以应用于字段或属性。
  • ElementType.METHOD 可应用于方法级批注。
  • ElementType.PARAMETER 可应用于该方法的参数。
  • ElementType.CONSTRUCTOR 可以应用于构造函数。
  • ElementType.LOCAL_VARIABLE 可以应用于局部变量。
  • ElementType.ANNOTATION_TYPE 可应用于注释类型。
  • ElementType.PACKAGE 可应用于包声明。
  • ElementType.TYPE_PARAMETER
  • ElementType.TYPE_USE

4、 @Inherited

@Inherited 注释指示注释类型可以从超类继承。当用户查询评论类型并且类没有这种类型的评论时,查询类的超类以获得评论类型(不是默认的)。此注释仅适用于类声明。

5、 @Repeatable

Repeatable Java SE 8引入, @Repeatable 注释指示标记的注释可以多次应用于同一声明或类型。(也就是说,它可以在相同的类、方法、属性等上重复使用。)。

自定义注释

Java中自定义注释和创建一个接口相似,自定义注释的格式是以@interface有记号的。

复制代码

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface SPI {
    /**
     * default extension name
     */
    String value() default "";
}

我们知道java.lang.annotation包裹里有一件。Annotation的接口,它是所有注解类型扩展的公共接口。那我们是否可以直接通过实现该接口来实现自定义注释呢?

复制代码

import java.lang.annotation.Annotation;
public class MyAnnotation implements Annotation {
    @Override
    public Class annotationType() {
        return null;
    }
}

发现Annotation只有一个接口annotationType方法,通过源代码注释我们可以发现答案是否定的。

中文译文如下:Annotaion由所有批注类型继承,但请注意,手动扩展继承此接口的接口并不定义批注类型。还要注意的是,该接口本身并没有定义注释类型。

使用场景

自定义注释的使用场景很多,我们在造轮子写框架的过程经常会使用到,例如我最近就遇到了一个业务场景:像一些编辑业务信息的接口,产品要求信息编辑后的新旧值对比,对比的业务功能,我们的实现方式是拿到前端填写的Form表单(新值)并对数据库进行查询。Dto(旧值)通过反射技术获得相同的属性字段名,并通过比较属性值获得新旧的值。在获得值之后,我们还知道该字段的Dto但如何将新旧值域的中文名返回到前端呢?例如:

复制代码

public class Stedent {
        private String name;
        private int age;
        private String sex;
       //省略setter,getter
    }

经过比较,我们的结果是 name : "xiaoming "-> "daming",age : 24 -> 26。但我们不能直接name和age返回到前端,他们需要的格式是:名称: "xiaoming "-> "daming",年龄 : 24 -> 26。这是您可以考虑自定义注释的地方。 @FieldName ,

复制代码

@Deprecated
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldName {
    String value() default "";
}

然后将注释添加到属性字段的上方。

复制代码

public class Student {

    @FieldName(value = "姓名")
    private String name;

    @FieldName(value = "年龄")
    private int age;

    @FieldName(value = "性别")
    private String sex;

    //省略setter,getter
}

然后,可以通过反射获得该字段的中文名称。

复制代码

// 如果 oldField 属性值与 newField 属性值的内容不相同。
if (!isEmpty(newValue)) {
    Map map = new HashMap<>();
    String newFieldName = newField.getName();

    //在这里获取注释的信息。
    if (newField.isAnnotationPresent(FieldName.class)) {
        FieldName fieldNameAnno = newField.getAnnotation(FieldName.class);
        newFieldName = fieldNameAnno.name();
    }
        map.put(FIELD_NAME, newFieldName);
        map.put(OLD_VALUE, oldValue);
        map.put(NEW_VALUE, newValue);
        list.add(map);
}
版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除

上一篇:栈帧的一些归纳 下一篇:idea常用快捷键
热门