今天在慕课网学了java注解,想着做一篇总结博客,无意中看到“还记得梦想吗”博主也做了慕课网教程的总结,我就拿过来直接用啦^_^,谢谢原博主的辛劳总结,以下呢就是在此基础上做了一下小小的调整。
原文链接:https://blog.csdn.net/jianjiaqqq001/article/details/73440822
jdk自带的注解
- 重写注解 @Override 会按注解指令 覆盖 父类中的一个类,如果没有覆盖就会报编译错误
- 方法过时注解 @Deprecated
- 消除警告注解@SuppressWarnings
- 函数式接口注解@Functionallnterface。jdk1.8引入。
按照运行机制来分
1.源码注解
注解只在源码中存在,编译成.class文件就不存在了
2.编译时注解
注解在源码和.class文件都存在
例如@Override @Deprecated @SuppressWarnings(“”)
3.运行时注解
在运行阶段还起作用,甚至会影响运行逻辑的注解
4.元注解 注解的注解
使用自定义注解
先定义以上的注解 然后再代码中使用定义的注解
注意:
注解 是 无参无异常 的声明 可以有默认值 ,注解只有一个方法时 要用value ,当只有一个的时候 可以直接使用 ,没有任何成员的时候就是标识注解。
@Documented 就是标识注解
注解的属性
注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无参无异常的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
int id();
String msg();
}
上面代码定义了 TestAnnotation 这个注解中拥有 id 和 msg 两个属性。在使用的时候,我们应该给它们进行赋值。赋值的方式是在注解的括号内以 value="" 形式,多个属性之前用 ,隔开。
@TestAnnotation(id=3,msg="hello annotation")
public class Test {
}
需要注意的是,在注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组。
注解中属性可以有默认值,默认值需要用 default 关键值指定。比如:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
public int id() default -1;
public String msg() default "Hi";
}
TestAnnotation 中 id 属性默认值为 -1,msg 属性默认值为 Hi。
它可以这样应用。
@TestAnnotation()
public class Test {}
因为有默认值,所以无需要再在 @TestAnnotation 后面的括号里面进行赋值了,这一步可以省略。
另外,还有一种情况。如果一个注解内仅仅只有一个名字为 value 的属性时,应用这个注解时可以直接接属性值填写到括号内。
public @interface Check {
String value();
}
上面代码中,Check 这个注解只有 value 这个属性。所以可以这样应用。
@Check("hi")
int a;
这和下面的效果是一样的
@Check(value="hi")
int a;
最后,还需要注意的一种情况是一个注解没有任何属性。比如
public @interface Perform {}
那么在应用这个注解的时候,括号都可以省略。
@Perform
public void testMethod(){}
注解使用范围
- 类属性自动赋值。
- 验证对象属性完整性。
- 代替配置文件功能,像spring基于注解的配置。
- 可以生成文档,像java代码注释中的@see,@param等
解析注解
概念: 通过反射获取类,函数或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑。
//描述注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description {String value();
}
//父类
public abstract class Person {
public abstract String name();
}//小孩类 子类
@Description("I am class annotation")
public class Child extends Person{@Override
@Description("I am method annotation")
public String name() {
return null;
}}
//注解解析类
public class ParseAnn {
public static void praseAnno(){
//1.使用类加载器加载类
try {
Class<?> clazz = Class.forName("com.danjiang.ann.Child");
//2.找到类上面的注解
boolean isAnnotationPresent = clazz.isAnnotationPresent(Description.class);
if (isAnnotationPresent) {
//3.拿到注解实例
Description annotation = clazz.getAnnotation(Description.class);
String value = annotation.value();
System.out.println("value==" + value);
}//4.找到方法上的注解
Method[] methods = clazz.getMethods();
for (Method method : methods) {
//2.找到方法上面的注解
boolean isExit = method.isAnnotationPresent(Description.class);
if (isExit) {
//3.拿到注解实例
Description annotation = method.getAnnotation(Description.class);
String value = annotation.value();
System.out.println("value==" + value);
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}}
// 执行
public static void main(String[] args) {
ParseAnn.praseAnno();
}
运行结果 :
value==I am class annotation
value==I am method annotation//另外的一种解法
for (Method method : methods) {
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof Description) {
String value = ((Description) annotation).value();
System.out.println(value);
}
}
}
这是运行时注解。 假如我们改成Source , Class
运行时就没有了.
@Inhrited
是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation
当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
@Description("I am class Person annotation")
public abstract class Person {
@Description("I am method annotation")
public abstract String name();
}public class Child extends Person{
@Override
public String name() {
return null;
}}
运行结果:value==I am class Person annotation
抽象类 Person 改成接口后什么也不输出
在接口上是不起做用的,在父类上会起作用 而且只继承了类上的注解,没有继承方法上的注解。
公司取自一个公司的持久层框架,用来代替Hibernate的解决方案,核心代码用注解来实现。
实例
需求:
1.用户有一张表,字段包括用户ID,用户名,昵称,年龄,性别,所在城市,邮箱,手机号。
2.方便的对每个字段或字段的组合条件进行检索,并打印SQL
3.使用的方式要足够简单
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {String value();
}
package com.danjian.test;
@Table("user")
public class Filter {
@Column("id")
private int id;
@Column("user_name")
private String userName;
@Column("nick_name")
private String nickName;
@Column("age")
private int age;
@Column("city")
private String city;
@Column("email")
private String email;
@Column("mobile")
private String mobile;public int getId() {
return id;
}public void setId(int id) {
this.id = id;
}public String getUserName() {
return userName;
}public void setUserName(String userName) {
this.userName = userName;
}public String getNickName() {
return nickName;
}public void setNickName(String nickName) {
this.nickName = nickName;
}public int getAge() {
return age;
}public void setAge(int age) {
this.age = age;
}public String getCity() {
return city;
}public void setCity(String city) {
this.city = city;
}public String getEmail() {
return email;
}public void setEmail(String email) {
this.email = email;
}public String getMobile() {
return mobile;
}public void setMobile(String mobile) {
this.mobile = mobile;
}}
public class MainTest {
public static void main(String[] args) {
Filter filter1 = new Filter();
Filter filter2 = new Filter();
Filter filter3 = new Filter();
filter1.setId(10); //查询id为10的用户filter2.setUserName("lucy"); //查询用户名为Lucy的用户
filter2.setNickName("jiang"); //查询用户名为Lucy的用户filter3.setEmail("aaa@163.com,bbb@163.com,bbb@163.com");//查询邮箱为其中任意一个的
String sql1 = query(filter1);
String sql2 = query(filter2);
String sql3 = query(filter3);
System.out.println(sql1);
System.out.println(sql2);
System.out.println(sql3);
FilterTest filterTest = new FilterTest();
filterTest.setLeader("danjiang");
String sql4 = query(filterTest);
System.out.println(sql4);
}private static String query(Object filter) {
StringBuilder stringBuilder = new StringBuilder();
//1.获取到class
Class clazz = filter.getClass();
//2.获取Table的名字
boolean isAnnotationPresent = clazz.isAnnotationPresent(Table.class);
if (isAnnotationPresent) {
Table annotation = (Table) clazz.getAnnotation(Table.class);
String tableName = annotation.value();
stringBuilder.append("select * from ")
.append(tableName).append(" where 1 = 1");
//3.遍历所有字段
Field[] declaredFields = clazz.getDeclaredFields();
//4.处理每个字段对应的sql
//4.1拿到字段名for (Field field : declaredFields) {
boolean isexit = field.isAnnotationPresent(Column.class);
if (isexit) {
//4.1拿到字段名
Column annotationColumn = field.getAnnotation(Column.class);
String columName = annotationColumn.value();
// System.out.println("columName == " + columName);
//4.2拿到字段的值
String fielfName = field.getName();
// System.out.println("fielfName == " + fielfName);
//4.3拼接方法
String getMerhodName = "get" + fielfName.substring(0,1).toUpperCase() + fielfName.substring(1);
// System.out.println("getMerhodName == " + getMerhodName);
Object fieldValue = null;
try {
Method method = clazz.getMethod(getMerhodName);
fieldValue = method.invoke(filter);
// System.out.println("fieldValue == " + fieldValue);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}// 4.4拼装sql
if (fieldValue == null || (fieldValue instanceof Integer && (Integer)fieldValue == 0)) {
continue;
}
stringBuilder.append(" and ").append(columName);
if (fieldValue instanceof String) {
String newfieldValue = (String) fieldValue;
if (newfieldValue.contains(",")) {
String[] splits = newfieldValue.split(",");
stringBuilder.append(" in (");
for (String string : splits) {
stringBuilder.append("'").append(string).append("'").append(",");
}
stringBuilder.deleteCharAt(stringBuilder.length() -1);
stringBuilder.append(")");
// System.out.println(stringBuilder.toString());
} else {
stringBuilder.append(" = ").append("'").append(newfieldValue).append("'");
// System.out.println(stringBuilder.toString());
}
} else if (fieldValue instanceof Integer) {
stringBuilder.append(" = ").append(fieldValue);
// System.out.println(stringBuilder.toString());
}
}
}}
String sql = stringBuilder.toString();
return sql;
}
}
package com.danjian.test;
@Table("tepartment")
public class FilterTest {
@Column("id")
private int id;
@Column("name")
private String name;
@Column("leader")
private String leader;
@Column("amount")
private int 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 String getLeader() {
return leader;
}
public void setLeader(String leader) {
this.leader = leader;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}}
//运行结果:
select * from user where 1 = 1 and id = 10
select * from user where 1 = 1 and user_name = 'lucy' and nick_name = 'jiang'
select * from user where 1 = 1 and email in ('aaa@163.com','bbb@163.com','bbb@163.com')
select * from tepartment where 1 = 1 and leader = 'danjiang'