TVI-Android技术篇之注解Annotation

mac2022-06-30  125

开幕:初见

首先看一下家喻户晓的@Override注解:添加此注解,如果是非覆写的方法,就会报错
@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
再先看一下@Deprecated注解:添加此注解,如果是过时的方法,就会画线提示
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE}) public @interface Deprecated { String since() default ""; boolean forRemoval() default false; }
我们这个群体应该很擅长归纳事物的共性,然后总结出一丝规律
可以看到的是: public @interface 注解名{ } 因此,可依照这样自己写一个注解类: public @interface APerson { } 然后新建一个Person类看看能不能用: @APerson public class Person { }
编译器没报错,看了可以,于是你的第一个没用的注解就由此诞生,开幕止。

第一幕:相识:

原标签
1:@Retention(注解存活期):接受一个RetentionPolicy类型的枚举常量
//源码的RetentionPolicy枚举 public enum RetentionPolicy { /** * Annotations are to be discarded by the compiler. * 注解将会被编译器删除 */ SOURCE, /** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior. * 编译器会将注解保留在字节码文件中,但VM不会再运行期间保留它。这是默认行为 */ CLASS, /** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, so they may be read reflectively. * 编译器会将注解保留在字节码文件中,VM也会在运行期间保留它。(所以他们可以通过反射性被读取) * @see java.lang.reflect.AnnotatedElement */ RUNTIME }
创建一个运行期的注解
@Retention(RetentionPolicy.RUNTIME) public @interface APerson { }
2:@Target(目标):接受一个ElementType类型的枚举常量
//源码枚举类:ElementType public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ //声明类,接口(包括注解类型),或者枚举 TYPE, /** Field declaration (includes enum constants) */ //声明字段(包括枚举常量) FIELD, /** Method declaration */ //声明方法 METHOD, /** Formal parameter declaration */ //声明方法参数 PARAMETER, /** Constructor declaration */ //声明构造函数 CONSTRUCTOR, /** Local variable declaration */ //声明局部变量 LOCAL_VARIABLE, /** Annotation type declaration */ //声明注解 ANNOTATION_TYPE, /** Package declaration */ //声明包 PACKAGE, /** * Type parameter declaration * 声明参数类型 * @since 1.8 */ TYPE_PARAMETER, /** * Use of a type * * @since 1.8 */ TYPE_USE, /** * Module declaration. * 声明模块 * @since 9 */ MODULE }
3:@Inherited(继承):子类继承父类的注解
4:@Repeatable(可重复)
5:@Documented:能够将注解中的元素包含到 Javadoc。
已经同注解进行了基本的对话(了解),第二幕止。

第三幕:交涉

改善一下我们的注解
package top.toly.注解; import java.lang.annotation.*; /** * 作者:张风捷特烈 * 时间:2018/5/22:8:20 * 邮箱:1981462002@qq.com * 说明:注解类 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface APerson { public String name() default "捷特"; public int age() default 24; }
使用反射获取APerson对象,再得到其方法
package top.toly.注解; /** * 作者:张风捷特烈 * 时间:2018/5/22:8:21 * 邮箱:1981462002@qq.com * 说明:注解测试端 */ @APerson(name = "捷特", age = 24) public class Person { APerson aPerson = getClass().getAnnotation(APerson.class); public void say() { String name = aPerson.name(); int age = aPerson.age(); System.out.println("my name is "+name+",and I am "+age+"years old"); } public static void main(String[] args) { Person person = new Person(); person.say(); } }
输出结果
my name is 捷特,and I am 24 years old.
现在测试一下@Inherited(继承):
package top.toly.注解; /** * 作者:张风捷特烈 * 时间:2018/5/22:8:21 * 邮箱:1981462002@qq.com * 说明:注解测试端 */ @APerson(name = "捷特", age = 24) public class Person { APerson aPerson = getClass().getAnnotation(APerson.class); public void say() { String name = aPerson.name(); int age = aPerson.age(); System.out.println("my name is "+name+",and I am "+age+" years old."); } public static void main(String[] args) { Student student = new Student(); student.say(); } } class Student extends Person { }
运行:报错
Exception in thread "main" java.lang.NullPointerException at top.toly.注解.Person.say(Person.java:14) at top.toly.注解.Person.main(Person.java:22)
添加@Inherited注解
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Inherited public @interface APerson { public String name() default "捷特"; public int age() default 24; }
运行:
// my name is 捷特,and I am 24 years old.
这时你已经可以通过注解来获取信息了

第四幕:共鸣

人类创造了刀,有些人用它雕精美的艺术品,有人依靠它成为江湖浪客,有人以它护生,有人用它杀生。 成败善恶并非工具的荣辱,也非是锻造它的人,一切只取决于握刀人的本性与技艺。

下面通过两个简单示例实战一下

示例一:声明:下面的案例借鉴并修改于:https://blog.csdn.net/briblue/article/details/73824058
package top.toly.注解; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** * 作者:张风捷特烈 * 时间:2018/5/22:10:16 * 邮箱:1981462002@qq.com * 说明:注解类 */ @Retention(RetentionPolicy.RUNTIME) public @interface ADebug { } package top.toly.注解; import java.lang.reflect.Method; /** * 作者:张风捷特烈 * 时间:2018/5/22:10:17 * 邮箱:1981462002@qq.com * 说明:测试工具类 */ public class Debug { public static void debug(String clazz_name) { Class<?> clazz = null;//获取测试类字节码文件 Object testobj = null;//通过字节码获取实例 try { clazz = Class.forName(clazz_name); testobj = clazz.newInstance(); } catch (Exception e) { e.printStackTrace(); } Method[] method = clazz.getDeclaredMethods();//通过字节码获取所有方法 //用来记录测试产生的 log 信息 StringBuilder log = new StringBuilder(); // 记录异常的次数 int errornum = 0; for (Method m : method) { // 只有被 @ADebug 标注过的方法才进行测试 if (m.isAnnotationPresent(ADebug.class)) { try { m.setAccessible(true); m.invoke(testobj, null);//执行方法 } catch (Exception e) { errornum++; log.append("错误"+errornum+":"+m.getName()+"() has error:"); log.append("\n\r caused by "); //记录测试过程中,发生的异常的名称 log.append(e.getCause().getClass().getSimpleName()); log.append("\n\r"); //记录测试过程中,发生的异常的具体信息 log.append(e.getCause().getMessage()); log.append("\n\r"); } } } log.append(clazz.getSimpleName()); log.append(" has "); log.append(errornum); log.append(" error."); // 生成测试报告 System.out.println(log.toString()); } } package top.toly.注解; /** * 作者:张风捷特烈 * 时间:2018/5/22:10:18 * 邮箱:1981462002@qq.com * 说明:待测试类 */ public class BugTest { @ADebug public void say(){ System.out.println(Integer.parseInt("a")); } @ADebug public void jia(){ System.out.println("1+1="+1+1); } @ADebug public void jian(){ System.out.println("1-1="+(1-1)); } @ADebug public void cheng(){ System.out.println("3 x 5="+ 3*5); } @ADebug public void chu(){ System.out.println("6 / 0="+ 6 / 0); } public void resay(){ say(); } } package top.toly.注解; /** * 作者:张风捷特烈 * 时间:2018/5/22:10:28 * 邮箱:1981462002@qq.com * 说明:运行端 */ public class Client { public static void main(String[] args) { Debug.debug("top.toly.注解.BugTest"); } }

输出:

1-1=0 3 x 5=15 1+1=11 错误1:say() has error: caused by NumberFormatException For input string: "a" 错误2:chu() has error: caused by ArithmeticException / by zero BugTest has 2 error. 可以看到未加注解的方法,即使错了也不会检查到。 注解更像提示你一下到这要不要做些什么事,具体逻辑还需要具体的类来实现。 唯一的优势在于你知道了程序已经运行到注解处,还有你可以获取到注解中的字段值。
示例二:根据一个bean对象,来输处MySQL的查询语句
1.数据库列(字段)注解
package top.toly.注解.test; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 作者:张风捷特烈 * 时间:2018/5/22:23:27 * 邮箱:1981462002@qq.com * 说明:数据库列(字段)注解 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Column { String value(); }
2.数据库表注解
package top.toly.注解.test; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 作者:张风捷特烈 * 时间:2018/5/22:23:27 * 邮箱:1981462002@qq.com * 说明:数据库表注解 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Table { String value(); }
3.bean对象Sworld:曾经创建过一个sword的数据库,正好拿来用。(对MySQL不熟悉的可以看我的MySQL篇)
package top.toly.注解.test.bean; import top.toly.注解.test.Column; import top.toly.注解.test.Table; /** * 作者:张风捷特烈 * 时间:2018/5/23:14:47 * 邮箱:1981462002@qq.com * 说明: */ @Table("sword") public class Sword { @Column("id") private int id; @Column("name") private String name; @Column("atk") private int atk; @Column("hit") private int hit; @Column("crit") private int crit; @Column("attr_id") private int attr_id; @Column("type_id") private int type_id; 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 int getAtk() { return atk; } public void setAtk(int atk) { this.atk = atk; } public int getHit() { return hit; } public void setHit(int hit) { this.hit = hit; } public int getCrit() { return crit; } public void setCrit(int crit) { this.crit = crit; } public int getAttr_id() { return attr_id; } public void setAttr_id(int attr_id) { this.attr_id = attr_id; } public int getType_id() { return type_id; } public void setType_id(int type_id) { this.type_id = type_id; } }
4.核心类:QueryUtil:使用注解辅助得到查询语句
package top.toly.注解.test; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * 作者:张风捷特烈 * 时间:2018/5/23:14:53 * 邮箱:1981462002@qq.com * 说明:使用注解辅助得到查询语句 */ public class QueryUtil { public static String query(Object o) { StringBuffer sb = new StringBuffer(); //1.获取class Class<?> aClass = o.getClass(); //2.获取表名 boolean exist = aClass.isAnnotationPresent(Table.class); if (exist) { Table table = aClass.getAnnotation(Table.class); String tableName = table.value(); sb.append("SELECT * FROM ").append(tableName).append(" WHERE 1=1"); //3.遍历字段 Field[] fields = aClass.getDeclaredFields(); for (Field field : fields) { //4.处理字段对应的sql boolean b = field.isAnnotationPresent(Column.class); if (!b) { continue; } Column column = field.getAnnotation(Column.class); String columnName = column.value(); String fieldName = field.getName(); String getMethodName = "get" + fieldName.substring(0, 1) .toUpperCase() + fieldName.substring(1); Object fieldValue = null; try { Method getMethod = aClass.getMethod(getMethodName); fieldValue = getMethod.invoke(o); } catch (Exception e) { e.printStackTrace(); } //拼装sql if (fieldValue == null || (fieldValue instanceof Integer && (Integer) fieldValue == 0)) { continue; } sb.append(" and ").append(fieldName); if (fieldValue instanceof String) { String value = (String) fieldValue; if (value.contains(",")) { String[] strings = value.split(","); sb.append(" in("); for (String string : strings) { sb.append("'").append(string).append("'").append(","); } sb.deleteCharAt(sb.length() - 1); sb.append(")"); }else { sb.append("=").append("'" + fieldValue + "'"); } }else { sb.append("=").append(fieldValue); } } } return sb.toString(); } }
5.测试端
package top.toly.注解.test; import top.toly.注解.test.bean.Sword; /** * 作者:张风捷特烈 * 时间:2018/5/23:14:54 * 邮箱:1981462002@qq.com * 说明:测试端 */ public class Client { public static void main(String[] args) { Sword sabar = new Sword(); sabar.setName("炽燃"); sabar.setAtk(2000); System.out.println(QueryUtil.query(sabar)); } }
6.打印结果
SELECT * FROM sword WHERE 1=1 and name='炽燃' and atk=2000
用MySQL验证一下:
20180523152021788.png

终幕


后记、

1.声明:

[1]本文由张风捷特烈原创,转载请注明 [2]欢迎广大编程爱好者共同交流 [3]个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正 [4]你的喜欢与支持将是我最大的动力

2.连接传送门:

更多安卓技术欢迎访问:安卓技术栈 我的github地址:欢迎star 简书首发,腾讯云+社区同步更新 张风捷特烈个人网站,编程笔记请访问:http://www.toly1994.com

3.联系我

QQ:1981462002 邮箱:1981462002@qq.com 微信:zdl1994328

4.欢迎关注我的微信公众号,最新精彩文章,及时送达:
公众号.jpg

转载于:https://www.cnblogs.com/toly-top/p/9781885.html

相关资源:laravel-tvi:用于创建和管理网站的基本CMS。 使用Laravel,Tailwind,Vue和Inertia-源码
最新回复(0)