Java系列文章目录
IDEA使用指南
Java泛型总结(快速上手详解)
Java Lambda表达式总结(快速上手详解)
Java Optional容器总结(快速上手图解)
Java 自定义注解笔记总结(油管)
Java 抽象知识笔记总结(油管)
Java 抽象相关知识笔记
文章目录
- Java系列文章目录
- 一、前言
- 二、学习内容:
- 三、问题描述
- 四、解决方案:
- 4.1 自定义注解引入
- 4.2 自定义注解使用
- 4.2.1 自定义注解概念
- 4.2.2 自定义注解内部的属性
- 五、总结:
- 5.1 学习总结:
一、前言
目的:学习自定义注解相关内容
- 对油管博主John讲解的注解相关知识进行笔记总结
二、学习内容:
- 自定义注解的使用
三、问题描述
- 自定义注解没有实践经验
四、解决方案:
4.1 自定义注解引入
主要了解自定义注解如何创建以及如何使用
引入自定义注解的意义:
- 增强可读性:使代码更清晰,便于理解。
- 元编程:运行时动态获取注解信息,调整程序行为。
- 减少重复代码:简化配置和逻辑,提升开发效率。
- 框架集成:与框架(如Spring)自然结合,简化开发。
- 参数验证:验证用户输入的合法性。
- 文档生成:自动生成接口和文档。
- 配置管理:结合逻辑与配置,便于维护。
参考代码如下:
package org.example;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Main {
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
Cat mycat = new Cat("Kitty");
Dog mydog = new Dog("Jerry");
if (mydog.getClass().isAnnotationPresent(VeryImportant.class))
{
System.out.println("This is a very important dog!");
} else {
System.out.println("This is not a very important dog!");
}
for (Method method :mycat.getClass().getDeclaredMethods())
{
if (method.isAnnotationPresent(RunImmediately.class))
{
RunImmediately annotation = method.getAnnotation(RunImmediately.class);
for (int i = 0; i < annotation.times(); i++) {
method.invoke(mycat);
}
}
}
for (Field declaredField : mycat.getClass().getDeclaredFields()) {
if (declaredField.isAnnotationPresent(ImportantString.class))
{
Object value = declaredField.get(mycat);
if (value instanceof String)
{
System.out.println(value.toString().toUpperCase());
}
}
}
}
}
- 将对这三个分别在类,方法与字段上的注解的使用方法进行讲解
package org.example;
@VeryImportant
public class Cat {
@ImportantString
String name;
int age;
public Cat(String name) {
this.name = name;
}
@RunImmediately(times = 3)
public void meow() {
System.out.println("Meow");
}
public void eat() {
System.out.println("Eating");
}
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RunImmediately {
int times();
}
@Target({ElementType.TYPE, ElementType.METHOD})
//实际运行时保留此注解,其他代码可以查看这个注释并在运行时通过反射使用他
//Source 开始编译代码前删除这个注释 处理警告
//CLASS 编译过程保留注释 运行时抛弃
@Retention(RetentionPolicy.RUNTIME)
public @interface VeryImportant {
}
Dog是参考类
- 我们学习使用像下面这样的自定义注解
4.2 自定义注解使用
4.2.1 自定义注解概念
自定义注解在编程中主要用于提供额外的信息或元数据,它们并不直接参与程序的运行,而是供编译器、构建工具或其他处理程序在编译期间或运行时解析。
使用场景:
- 增强代码可读性:通过注解,开发者可以为特定代码块添加上下文相关的描述,帮助其他人更好地理解代码的功能。
- 配置信息传递:在框架或库中,注解可以作为配置选项,用于指定组件的行为、路径或者其他需要动态设置的属性。
- AOP(面向切面编程)支持:一些注解用于通知AOP框架进行切面的插入,比如@AspectJ注解。
- 元数据收集:注解可以帮助系统收集关于代码结构、依赖关系等非功能性信息,便于分析、调试和性能优化。
- 未来扩展:如果需要为现有代码预留扩展空间,自定义注解可以避免硬编码,方便后续修改。
主要学习下面两个元注解:
@Target 定义注解作用的位置
- ElementType.ANNOTATION_TYPE: 说明该注解只能应用于其他注解类型。
- ElementType.FIELD: 用于字段(变量)上。
- ElementType.METHOD: 用于方法上。
- ElementType.PARAMETER: 用于方法参数上。
- ElementType.CONSTRUCTOR: 用于构造函数上。
- ElementType.TYPE: 用于类、接口或异常声明上。
- ElementType.PACKAGE: 用于包上。
- ElementType.LOCAL_VARIABLE: 用于局部变量上。
- ElementType.MEMBER_CLASS: 用于成员内部类上。
@Retention 定义了注解应该在哪些级别保留其有效性
-
RUNTIME: 表示该注解在运行时仍然可见,并且可以通过反射API获取到。
-
SOURCE: 只在源代码级别有效,编译后会被丢弃。这种类型的注解通常用于编译器插件或生成其他源代码的时候。
-
CLASS: 仅在类加载时生效,在类加载完成并初始化后就不再可用。这意味着只有类文件级别的注解才会被保留。
- 如果没有ElementType.METHOD就会报错
- 观察结果
4.2.2 自定义注解内部的属性
- 观察可知自定义注解里面参数是函数形式的
如果没有默认值则使用的时候必须写出
- 同理关于字段的注解
五、总结:
5.1 学习总结:
- 注解的定义
自定义注解使用@interface关键字进行定义,并可以包含一些成员方法,通常用于定义额外的参数。
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME) // 指定注解的保留策略
public @interface MyAnnotation {
String value() default ""; // 默认值
int number() default 0; // 另一个属性
}
- 注解的保留策略
RetentionPolicy.SOURCE:注解只会保留在源代码中,编译后会被丢弃。
RetentionPolicy.CLASS:注解会被保留在class文件中,但在运行时不可用。
RetentionPolicy.RUNTIME:注解会被保留在class文件中,在运行时可以通过反射读取。
- 注解的使用
可以将自定义注解应用于类、方法、字段、参数等。
@MyAnnotation(value = "example", number = 5)
public class MyClass {
@MyAnnotation(value = "method")
public void myMethod() {
}
}
- 读取注解
可以通过Java反射机制读取注解的信息。
import java.lang.reflect.Method;
public class AnnotationProcessor {
public static void main(String[] args) {
Class<MyClass> obj = MyClass.class;
// 读取类的注解
if (obj.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = obj.getAnnotation(MyAnnotation.class);
System.out.println("Class Annotation: " + annotation.value() + ", " + annotation.number());
}
// 读取方法的注解
try {
Method method = obj.getMethod("myMethod");
if (method.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
System.out.println("Method Annotation: " + annotation.value());
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
- 注解的元注解
在定义自定义注解时,可以使用元注解来指定注解的特性,常见的元注解有:
@Retention:指定注解的保留策略。
@Target:指定注解可以应用在什么地方(类、方法、字段等)。
@Documented:表明将注解包含在JavaDoc中。
@Inherited:允许子类继承超类的注解。
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.METHOD) // 该注解只能用在方法上
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodInfo {
String author() default "unknown";
String date();
int revision() default 1;
}
- 注解示例
以下是一个简单的自定义注解示例,展示了如何定义和应用注解:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
String value() default "default test";
}
应用示例:
public class Example {
@Test(value = "This is a test method")
public void testMethod() {
System.out.println("Executing test method.");
}
}
(后续有遇到问题再添加)
声明:如本内容中存在错误或不准确之处,欢迎指正。转载时请注明原作者信息(麻辣香蝈蝈)。