Java 注解 Annotation自定义实战

简介: Java 注解 Annotation自定义实战

概念:

Java 提供的一种原程序中的元素关联任何信息和任何元数据的途径和方法

内容:

  1. Java 中常见的注解
  2. 注解分类
  3. 自定义注解
  4. 注解应用实战

一、Java 中常见的注解

1、JDK 自带注解

@Override 覆盖
@Deprecated 废弃
@SuppressWarnings 抑制警告

示例代码:

AnnotationDemo.java

package demo;



interface Human{
public void sayHello();
public void sayHi();
}


class Person implements Human{

@Override
public void sayHello() {
System.out.println("hello");
}

@Deprecated
@Override
public void sayHi() {
System.out.println("hi");
}
}


public class AnnotationDemo {
public static void main(String[] args) {
Person person = new Person();
person.sayHi();
}
}

以上代码执行编译的时候会有提示

$ javac AnnotationDemo.java
注: AnnotationDemo.java使用或覆盖了已过时的 API。
注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。


$ javac AnnotationDemo.java -Xlint:deprecation
AnnotationDemo.java:28: 警告: [deprecation] Person中的sayHi()已过时
person.sayHi();
^
1 个警告

可以抑制警告

public class AnnotationDemo {
@SuppressWarnings("deprecation")
public static void main(String[] args) {
Person person = new Person();
person.sayHi();
}
}

再次编译就没有提示了

2、常见的第三方注解

Spring

@Autowired
@Service
@Repository

MyBatis

@InsertProvider
@UpdateProvider
@Options

二、注解分类

1、按照运行机制分

  1. 源码注解 注解只存在于源码中,编译后成.class 文件就不存在了
  2. 编译时注解 注解在源码和.class 文件都存在
  3. 运行时注解 在运行阶段还起作用,会影响运行逻辑
    eg: @Autowired

2、按照来源分

  1. JDK 注解
  2. 第三方注解
  3. 自定义注解

元注解:注解的注解、

三、自定义注解

1、自定义注解语法

示例及说明

package demo;

import java.lang.annotation.*;

/**
* Target是注解作用域:
* TYPE 类,接口
* FIELD 字段声明
* METHOD 方法声明
* PARAMETER 参数声明
* CONSTRUCTOR 构造方法声明
* LOCAL_VARIABLE 局部变量声明
* ANNOTATION_TYPE
* PACKAGE 包声明
*
* Retention 生命周期
* SOURCE 只在源码显示,编译时会丢弃
* CLASS 编译时会记录到class中,运行时忽略
* RUNTIME 运行时存在,可以通过反射读取
*
* Inherited 允许子类继承
*
* Documented 生成javadoc时会包含注解信息
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
// 1、使用关键词@interface 定义注解
public @interface Description {
// 2、成员以无参无异常方式声明
String desc();

// 3、可以用default为成员指定默认值
int age() default 18;

// 4、成员类型是受限的,合法的类型包括原始类型及
// String, Class, Annotation, Enumeration
String author();
}
/**
* 5、如果注解只有一个成员,则成员名必须取名为: value()
* 在使用时可以忽略成员名和赋值号(=)
*
* 6、注解类可以没有成员,没有成员的注解称为 标识注解
*/

2、使用注解的语法

// @<注解名>(<成员名>=<成员值>...)

class Demo {
@Description(desc = "i am eyeColor", author = "Tom", age = 18)
public String eyeColor() {
return "red";
}

public static void main(String[] args) {

}
}

3、解析注解

概念:

通过反射获取类、函数或成员上运行时注解信息,从而实现动态控制程序运行的逻辑

package demo;

import java.lang.annotation.*;
import java.lang.reflect.Method;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description {
String value();
}

@Description("a class annotation")
class Demo {
@Description("a method annotation")
public String eyeColor() {
return "red";
}
}

class DemoTest {
public static void main(String[] args) throws ClassNotFoundException {
// 1、使用类加载器
Class clazz = Class.forName("demo.Demo");

// 2、找到类上面的注解
boolean isExist = clazz.isAnnotationPresent(Description.class);
if (isExist) {
// 3、拿到注解实例
Description description = (Description) clazz.getAnnotation(Description.class);
System.out.println(description.value());
// a class annotation
}

// 找到方法上的注解
Method[] methods = clazz.getMethods();
for (Method method : methods) {
boolean isMethodExist = method.isAnnotationPresent(Description.class);
if (isMethodExist) {
Description description = (Description) method.getAnnotation(Description.class);
System.out.println(description.value());
}
}

// 另一种解析方法
for (Method method : methods) {
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof Description) {
Description description = (Description) annotation;
System.out.println(description.value());
}
}
}
}
}

4、继承@Inherited

package demo;

import java.lang.annotation.*;
import java.lang.reflect.Method;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description {
String value();
}

@Description("a class annotation")
class Person {
@Description("a method annotation")
public String eyeColor() {
return "red";
}
}


class Child extends Person {
@Override
public String eyeColor() {
return "red";
}
}

// Child 继承 Person 可以获取类上面的注解

四、注解实战

1、项目说明


用注解实现持久层框架,替代 Hibernate 解决方案


2、需求:


有一张用户表,字段包括用户用户名,年龄,电话

方便对每个对象进行保存,并打印出 SQL。

使用方式要足够简单,见代码示例。

3、思路:


考虑代码如何与数据库进行映射

实现 save

4、代码实现


文件目录

.
├── Column.java
├── Demo.java
├── Table.java
└── User.java

Table.java

package anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

Column.java

package anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value();
}

User.java

package anno;

@Table("user")
public class User {
@Column("name")
private String name;

@Column("age")
private Integer age;

@Column("phone_number")
private String phoneNumber;

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 String getPhoneNumber() {
return phoneNumber;
}

public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
}

Demo.java

package anno;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Demo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
User user = new User();
user.setAge(12);

System.out.println(save(user));
//insert into `user` (`name`, `phone_number`, `age`) values('null', 'null', '12')
}

private static String save(User user) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 获取class
Class clazz = user.getClass();

// 获取表名
if (!clazz.isAnnotationPresent(Table.class)) {
return null;
}

StringBuilder builder = new StringBuilder();
builder.append("insert into ");

Table table = (Table) clazz.getAnnotation(Table.class);
String tableName = table.value();
builder.append("`").append(tableName).append("` ");

// 获取所有字段名和字段值
Map<String, String> map = new HashMap<>();

Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (!field.isAnnotationPresent(Column.class)) {
continue;
}

// 通过注解获取字段名称
Column column = field.getAnnotation(Column.class);
String columnName = column.value();

// 通过反射获取字段的值
String fieldName = field.getName();
String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
Method method = clazz.getMethod(methodName);
String columnValue = String.valueOf(method.invoke(user));

map.put(columnName, columnValue);
}

// 拼装sql
builder.append("(");
Object[] columns = map.keySet().toArray();
for (int i = 0; i < columns.length; i++) {
builder.append("`").append(columns[i].toString()).append("`");
if (i != columns.length - 1) {
builder.append(", ");
}
}

builder.append(") ");

builder.append("values");

builder.append("(");
Object[] values = map.values().toArray();
for (int i = 0; i < values.length; i++) {
builder.append("'").append(values[i].toString()).append("'");
if (i != values.length - 1) {
builder.append(", ");
}
}
builder.append(") ");

return builder.toString();
}
}

五、总结

1、认识注解


2、注解的作用范围@Target 和生命周期@Retention


(1)作用范围: 包、类、字段、方法、方法参数、局部变量


(2)生命周期:源文件 source,编译 class, 运行 runtime


3、读懂注解


4、使用注解解决实际开发问题


            </div>
目录
相关文章
|
8天前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
|
8天前
|
Java
在 Java 中,如何自定义`NumberFormatException`异常
在Java中,自定义`NumberFormatException`异常可以通过继承`IllegalArgumentException`类并重写其构造方法来实现。自定义异常类可以添加额外的错误信息或行为,以便更精确地处理特定的数字格式转换错误。
|
29天前
|
存储 Java 开发者
Java Map实战:用HashMap和TreeMap轻松解决复杂数据结构问题!
【10月更文挑战第17天】本文深入探讨了Java中HashMap和TreeMap两种Map类型的特性和应用场景。HashMap基于哈希表实现,支持高效的数据操作且允许键值为null;TreeMap基于红黑树实现,支持自然排序或自定义排序,确保元素有序。文章通过具体示例展示了两者的实战应用,帮助开发者根据实际需求选择合适的数据结构,提高开发效率。
60 2
|
29天前
|
XML Java 编译器
Java学习十六—掌握注解:让编程更简单
Java 注解(Annotation)是一种特殊的语法结构,可以在代码中嵌入元数据。它们不直接影响代码的运行,但可以通过工具和框架提供额外的信息,帮助在编译、部署或运行时进行处理。
86 43
Java学习十六—掌握注解:让编程更简单
|
1月前
|
存储 消息中间件 安全
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
【10月更文挑战第9天】本文介绍了如何利用JUC组件实现Java服务与硬件通过MQTT的同步通信(RRPC)。通过模拟MQTT通信流程,使用`LinkedBlockingQueue`作为消息队列,详细讲解了消息发送、接收及响应的同步处理机制,包括任务超时处理和内存泄漏的预防措施。文中还提供了具体的类设计和方法实现,帮助理解同步通信的内部工作原理。
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
|
23天前
|
Java 开发者 Spring
[Java]自定义注解
本文介绍了Java中的四个元注解(@Target、@Retention、@Documented、@Inherited)及其使用方法,并详细讲解了自定义注解的定义和使用细节。文章还提到了Spring框架中的@AliasFor注解,通过示例帮助读者更好地理解和应用这些注解。文中强调了注解的生命周期、继承性和文档化特性,适合初学者和进阶开发者参考。
44 14
|
23天前
|
前端开发 Java
[Java]讲解@CallerSensitive注解
本文介绍了 `@CallerSensitive` 注解及其作用,通过 `Reflection.getCallerClass()` 方法返回调用方的 Class 对象。文章还详细解释了如何通过配置 VM Options 使自定义类被启动类加载器加载,以识别该注解。涉及的 VM Options 包括 `-Xbootclasspath`、`-Xbootclasspath/a` 和 `-Xbootclasspath/p`。最后,推荐了几篇关于 ClassLoader 的详细文章,供读者进一步学习。
29 12
|
30天前
|
安全 Java
如何在 Java 中创建自定义安全管理器
在Java中创建自定义安全管理器需要继承SecurityManager类并重写其方法,以实现特定的安全策略。通过设置系统安全属性来启用自定义安全管理器,从而控制应用程序的访问权限和安全行为。
|
1月前
|
开发框架 Java 程序员
揭开Java反射的神秘面纱:从原理到实战应用!
本文介绍了Java反射的基本概念、原理及应用场景。反射允许程序在运行时动态获取类的信息并操作其属性和方法,广泛应用于开发框架、动态代理和自定义注解等领域。通过反射,可以实现更灵活的代码设计,但也需注意其性能开销。
47 1
|
17天前
|
Java 编译器
Java进阶之标准注解
Java进阶之标准注解
28 0