大学网站开发实验室建设方案,淳安县住房和城乡建设局网站首页,淮安网站建设找谁好,中国建筑网查询Java ”框架 注解 反射 设计模式“ 之 注解详解 每博一文案
刹那间我真想令时光停住#xff0c;好让我回顾自己#xff0c;回顾失去的年华#xff0c;缅怀哪个穿一身短小的连衣裙
和瘦窄的短衫的小女孩。让我追悔少年时代#xff0c;我心灵的愚钝无知#xff0c;它轻易…Java ”框架 注解 反射 设计模式“ 之 注解详解 每博一文案
刹那间我真想令时光停住好让我回顾自己回顾失去的年华缅怀哪个穿一身短小的连衣裙
和瘦窄的短衫的小女孩。让我追悔少年时代我心灵的愚钝无知它轻易地错过了我一生中本来
可以获得欢乐和幸福。—————— 《平凡的世界》真的如果痛苦不能改变生存那还不如平静地将自己毁灭毁灭一切都毁灭了
只有生命还在苟延残喘这样的生命还有有什么存在的价值。—————— 《平凡的世界》 文章目录Java ”框架 注解 反射 设计模式“ 之 注解详解每博一文案1. 注解的概念2. 注解的作用3. 文档注释中的注解4. 自定义注解4.1 注解中的属性4.2 注解中属性为数组的赋值5. JDK 内置的三个基本注解5.1 Override: 限定重写父类方法, 该注解只能用于方法5.2 Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。5.3 SuppressWarnings: 抑制编译器警告6. 元注解6.1 Target6.2 Retention6.3 Documented6.4 Inherited7. 通过反射获取到注解信息8. 总结:9. 最后1. 注解的概念
注解一种元数据形式提供了一个不属于程序本身的程序的数据。注解对他们注解的代码的操作没有直接的影响。
注解有很多用途其中
编译器的信息 - 编译器可以使用注解来检测错误或抑制警告。编译和部署时处理 - 软件工具可以处理注解信息以生成代码XML 文件等。运行时处理 - 一些注解可以在运行时检查
从 JDK5.0 开始Java增加了对元数据**(MetaData)** 的支持也就是 Annotation 注解。
注解: 其实就是代码里的 特殊标记 这些标记可以在编译类加载运行时被读取并执行相应的处理。通过使用 注解
程序员可以在不改变原有的逻辑的情况下在源文件种嵌入一些补充的信息。代码分析工具开发工具和部署工具可以通过这些补充信息进行验证或进行部署。 注解: 可以像修饰符一样被使用可以用于 修饰包类构造器方法成员变量参数局部变量的声明 。这些信息被保存在 注解 Annotaion 的“ name value” 键值对中。 在JavaSE中注解的使用目的比较简单例如标记过时的功能忽略警告等。在JavaEE/Android中注解占据了更重要的角色例如 用来配置应用程序的任何切面代替JavaEE旧版中所遗留的繁冗 代码和XML配置等。 未来的开发模式都是基于注解的JPA 是基于注解的Spring2.5 以上都是基于注解的Hibernate3.x 以后也是基于注解的
现在Struts2 有一部分也是基于注解的了。注解是一种趋势一定程度上可以说框架 注解 反射 设计模式 。
2. 注解的作用
从 JVM 的角度看注解本身对代码逻辑没有任何影响如何使用注解完全由工具决定。
Java的注解可以分为三类
第一类是由编译器使用的注解换句话说就是给编译器看的不是给 JVM 看的。例如 Override : 让编译器检查该方法是否正确的实现了 重写操作。Deprecated 表示所修饰的元素(类方法等)已过时了不建议使用它了。SuppressWarnings 告诉编译器忽略此处代码产生的警告。 第二类 是由工具处理 .class 文件使用的注解比如有些工具会在加载 class 的时候对 class 做动态修改实现一些特殊的功能。这类注解会被编译进入到 .class 文件但加载结束后并不会存在于内存中。这类注解只被一些底层使用一般我们不必自己处理。第三类 是在程序运行期间能够读取的注解它们在加载后一直存在于 JVM 中这也是最常用的注解。例如一个配置了PostConstruct 的方法会在调用构造方法后自动被调用(这是Java代码读取该注解实现的功能JVM 并不会识别该注解)。
3. 文档注释中的注解 author 标明开发该类模块的作者多个作者之间使用分割。version 标明该类的模块的版本。see 参考转向也就是相关类的主题。since 从哪个版本开始增加的。param 对方法中某参数的说明如果没有参数就不能写。return 对方法返回值的说明如果方法的返回值类型是 void 就不能写exception 对方法可能抛出的异常进行说明如果方法没有用 throws 显抛出的异常就不能写 其中 param return 和 exeption 这三个标记都是只用于方法的。param 的格式要求param 形参名 形参类型 形参说明return 的格式要求return 返回值类型 返回值说明exception 的格式要求exception 异常类型 异常说明 param 和 exception 可以并列多个。
4. 自定义注解
Annotaion注解 其实也是一种引用数据类型编译之后也是生成 xxx.class 字节码文件的。 定义新的 Annotation 注解 类型使用 interface 关键字 自定义注解自动实现了 java.lang.annotation.Annotation接口 自定义注解的格式如下:
public interface MyAnnotation {}//
[修饰列表] interface 注解名/(注解类名) {}使用 IDEA 创建一个 注解类型 鼠标右键 —— new 一个选择 : 如下查看该 我们该自定义的注解 MyAnnotation 的 UML 图可以清楚的看到该 注解类型是自动继承了该 java.lang.annotation.Annotation 接口的 但是事实上却是自动实现了 java.lang.annotation.Annotation 接口。 在Java 8之前注解只能是在声明的地方所使用Java8 开始注解可以应用 在任何地方 。这里的任何地方包括包类构造器方法成员变量参数局部变量的声明 。这些信息被保存在 注解 Annotaion 的“ name value” 键值对中。
举例如下 并没有出现任何的报错的情况。 4.1 注解中的属性
在注解中可以定义属性。
Java中的注解中的属性看着像方法但实际在注解当中是属性 name
格式如下
String value();
// 数据类型 属性名(); // 看似是方法其实在注解中是属性注解中的属性可以是任何类型byte short int long float double boolean char String long Class 枚举类型。再或者是自定义类型。
举例:
public interface MyAnnotation {String value();}
注意 如果该注解中定义了属性则声明使用该注解时 必须 为其注解中的属性值赋上值不然是会报错的。
如下我们为该 MyAnnotation 注解定义了属性使用时却没有赋值报如下编译错误。 为注解中的属性赋值的格式如下
MyAnnotaion(valueTom) // 注意在该注解中定义的是什么类型的值就赋值对应的值不然会报错的
// 注解名(注解中的属性名对应赋值的属性值)举例: 如果该注解中只有一个属性值并且该注解的属性名为 value 则在赋值时可以省略其 为value的属性名直接写值 。
注意一定要满足两个条件1. 该注解中只有一个属性值2.该属性名为 value
举例: 为注解中的多个属性赋值格式如下 多个属性值使用逗号分隔开来就可以了。 MyAnnotation(value Tom,value2 123)
// 注解名(注解中的属性名值,注解中的属性名值) 多个属性值使用逗号分隔开。注意 当注解中存在多个属性值时其中所有该注解中的属性值都必须赋值不然编译报错如下 必须将注解中的所有属性值都赋值上值才行如下如果注解中存在两个或两个以上的属性就算其中存在一个属性名为 value 其赋值时该value 属性名是不可以省略的。必须写明所有的属性名的进行赋值。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
注解中的属性可以设置默认值使用关键字格式如下
String value() default Tom;
// 数据类型 属性名() default 默认值; 注意需要和定义的类型保证一致。举例:
public interface MyAnnotation {String value() default Tom;}
注解中属性设置了默认值的是可以选择不进行赋值操作使用定义的默认值。
举例如下 4.2 注解中属性为数组的赋值
注解中的属性值是可以定义为数组属性的格式如下:
String[] arr(); // 定义数组为属性值
数据类型[] 属性名(); 举例:
public interface MyAnnotation {String value();String[] arr();}
注解中以数组为属性的赋值格式如下
MyAnnotation(value Tom,arr {hello,world})
注解名(属性名值,属性名{值,值})举例 当数组属性所赋值的参数只有一个时可以省略{} 花括号。如下 5. JDK 内置的三个基本注解
下面我们来认识一下JDK 中三个常见的基本注解。
5.1 Override: 限定重写父类方法, 该注解只能用于方法 Override : 的作用就是在编译期间让编译器检查该方法是否正确的实现了 重写 操作。其中的重写的方法名是否存在错误方法的返回值类型是否是父类中/接口中的一致。不一致编译报错提示我们改正。
OVerride 注解的源码可以看到该注解是没有定义属性的。
package java.lang;import java.lang.annotation.*;/*** Indicates that a method declaration is intended to override a* method declaration in a supertype. If a method is annotated with* this annotation type compilers are required to generate an error* message unless at least one of the following conditions hold:** ulli* The method does override or implement a method declared in a* supertype.* /lili* The method has a signature that is override-equivalent to that of* any public method declared in {linkplain Object}.* /li/ul** author Peter von der Aheacute;* author Joshua Bloch* jls 9.6.1.4 Override* since 1.5*/
Target(ElementType.METHOD)
Retention(RetentionPolicy.SOURCE)
public interface Override {
}
注意 该注解只能使用在方法上因为该注解的源码中被Target(ElementType.METHOD)元注解修饰了在其他位置上是会编译报错的。如下 OVerride 注解的使用: 较少了我们编程程序时上的简单符号上以及一些基本的语法错误。 5.2 Deprecated: 用于表示所修饰的元素(类, 方法等)已过时。 Deprecated : 该注解表示表示所修饰的元素(类方法等)已过时了不建议使用它了。建议替换成其他的方法。
Depecated 源码 可以看到该注解是没有定义属性的。
package java.lang;import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;/*** A program element annotated #64;Deprecated is one that programmers* are discouraged from using, typically because it is dangerous,* or because a better alternative exists. Compilers warn when a* deprecated program element is used or overridden in non-deprecated code.** author Neal Gafter* since 1.5* jls 9.6.3.6 Deprecated*/
Documented
Retention(RetentionPolicy.RUNTIME)
Target(value{CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public interface Deprecated {
}
常见的在我们的 java.util.lang 包下的 Date 中的 Date(String s) 构造器是被 Deprecated 注解修饰了的。 在IDEA 中 如果我们调用了被 Deprecated 修饰的属性方法构造器会给一个直观的将该属性/方法以删除线的方式显示处理并提示你建议使用别的方式替换 。如下 我们也可以自己写一个这样的被Deprecated 修饰的属性/方法/类/构造器。举例如下 5.3 SuppressWarnings: 抑制编译器警告 SuppressWarnings ** 指示应该在注解元素(以及包含在该注解元素中所有程序元素中的所有程序元素)中取消显示指定的编译器警告。换句话说就是告诉编译器忽略此处代码产生的警告**。 注意是警告不是异常。
SuppressWarnings的源码 可以看到该注解定义了一个名为 value 的属性。 package java.lang;import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;/*** Indicates that the named compiler warnings should be suppressed in the* annotated element (and in all program elements contained in the annotated* element). Note that the set of warnings suppressed in a given element is* a superset of the warnings suppressed in all containing elements. For* example, if you annotate a class to suppress one warning and annotate a* method to suppress another, both warnings will be suppressed in the method.** pAs a matter of style, programmers should always use this annotation* on the most deeply nested element where it is effective. If you want to* suppress a warning in a particular method, you should annotate that* method rather than its class.** author Josh Bloch* since 1.5* jls 4.8 Raw Types* jls 4.12.2 Variables of Reference Type* jls 5.1.9 Unchecked Conversion* jls 5.5.2 Checked Casts and Unchecked Casts* jls 9.6.3.5 SuppressWarnings*/
Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
Retention(RetentionPolicy.SOURCE)
public interface SuppressWarnings {/*** The set of warnings that are to be suppressed by the compiler in the* annotated element. Duplicate names are permitted. The second and* successive occurrences of a name are ignored. The presence of* unrecognized warning names is inot/i an error: Compilers must* ignore any warning names they do not recognize. They are, however,* free to emit a warning if an annotation contains an unrecognized* warning name.** p The string {code unchecked} is used to suppress* unchecked warnings. Compiler vendors should document the* additional warning names they support in conjunction with this* annotation type. They are encouraged to cooperate to ensure* that the same names work across multiple compilers.* return the set of warnings to be suppressed*/String[] value();
}
举例: 这里我们定义一个 int num 1 / 0 语句IDEA 该我们提示了警告了。 当我们加上了 SuppressWarnings IDEA 就没有这个警告了。如下 具体的其他应用大家可以移步至 https://blog.csdn.net/qq_43842093/article/details/122386115?ops_request_miscrequest_idbiz_id102utm_term%20SuppressWarnings%E7%9A%84%E4%BD%BF%E7%94%A8utm_mediumdistribute.pc_search_result.none-task-blog-2allsobaiduweb~default-3-122386115.142 Eclipse Galileo版本支持的抑制警告的名称
关键字用途allto suppress all warnings 抑制所有警告boxingto suppress warnings relative to boxing/unboxing operations 抑制装箱、拆箱操作时候的警告castto suppress warnings relative to cast operations 抑制映射相关的警告dep-annto suppress warnings relative to deprecated annotation 抑制启用注释的警告deprecationto suppress warnings relative to deprecation 抑制过期方法警告fallthroughto suppress warnings relative to missing breaks in switch statements 抑制确在switch中缺失breaks的警告finallyto suppress warnings relative to finally block that don’t return 抑制finally模块没有返回的警告hidingto suppress warnings relative to locals that hide variable抑制相对于隐藏变量的局部变量的警告incomplete-switchto suppress warnings relative to missing entries in a switch statement (enum case)忽略没有完整的switch语句nlsto suppress warnings relative to non-nls string literals 忽略非nls格式的字符nullto suppress warnings relative to null analysis 忽略对null的操作rawtypesto suppress warnings relative to un-specific types when using generics on class params 使用generics时忽略没有指定相应的类型restrictionto suppress warnings relative to usage of discouraged or forbidden references 抑制禁止使用劝阻或禁止引用的警告serialto suppress warnings relative to missing serialVersionUID field for a serializable class 忽略在serializable类中没有声明serialVersionUID变量static-accessto suppress warnings relative to incorrect static access 抑制不正确的静态访问方式警告synthetic-accessto suppress warnings relative to unoptimized access from inner classes 抑制子类没有按最优方法访问内部类的警告uncheckedto suppress warnings relative to unchecked operations 抑制没有进行类型检查操作的警告unqualified-field-accessto suppress warnings relative to field access unqualified 抑制没有权限访问的域的警告unusedto suppress warnings relative to unused code 抑制没被使用过的代码的警告
6. 元注解
有一些注解可以修饰其他注解这些注解就称为元注解meta annotation。Java标准库已经定义了一些元注解我们只需要使用元注解通常不需要自己去编写元注解。
6.1 Target Target 源码其中存在一个类型为 ElementType[] 枚举类型数组属性名为 value 的属性。
package java.lang.annotation;Documented
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.ANNOTATION_TYPE)
public interface Target {/*** Returns an array of the kinds of elements an annotation type* can be applied to.* return an array of the kinds of elements an annotation type* can be applied to*/ElementType[] value();
}
ElementType的枚举源码 :
/package java.lang.annotation;
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
}
Target : 最常用的元注解是Target。使用Target可以定义Annotation能够被应用于源码的哪些位置
类或接口ElementType.TYPE字段ElementType.FIELD方法ElementType.METHOD构造方法ElementType.CONSTRUCTOR方法参数ElementType.PARAMETER。
举例 Target元注解中的 value 属性是枚举数组类型的可以赋值多个值比如表示该注解可以声明在方法变量类中 举例 6.2 Retention Retention 源码 : 我们可以看到如下注解中只定义了一个RetentionPolicy 的枚举类型名为 value 的属性名的属性
package java.lang.annotation;Documented
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.ANNOTATION_TYPE)
public interface Retention {/*** Returns the retention policy.* return the retention policy*/RetentionPolicy value();
}
RetentionPolicy 枚举类型的源码
package java.lang.annotation;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.*/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.** see java.lang.reflect.AnnotatedElement*/RUNTIME
}
Retention : 另一个重要的元注解Retention定义了Annotation的生命周期
Rentention 时必须为该 value 成员变量指定值
仅编译期RetentionPolicy.SOURCE 表示该注解的生命周期只在编译期间有效在源文件中有效即源文件保留编译器直接丢弃这种策略的注释。仅class文件RetentionPolicy.CLASS 在class文件中有效即class保留 当运行 Java 程序时, JVM 不会保留注解。 这是默认值运行期RetentionPolicy.RUNTIME注意只有定义该属性的注解才能被反射读取到。上面两种方式都无法被反射读取到的。
如果Retention不存在则该Annotation默认为CLASS。因为通常我们自定义的Annotation都是RUNTIME所以务必要加上Retention(RetentionPolicy.RUNTIME)这个元注解
举例: 6.3 Documented Documented: 用于指定被该元 Annotation 修饰的 Annotation 类将被 javadoc 工具提取成文档。默认情况下javadoc是不包括注解的。
定义为Documented的注解必须设置Retention值为RUNTIME
Documented 的源码 从源码看该注解没有任何属性。 package java.lang.annotation;Documented
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.ANNOTATION_TYPE)
public interface Documented {
}
6.4 Inherited Inherited: 被它修饰的 Annotation 将具有继承性。如果某个类使用了被
Inherited : 修饰的 Annotation, 则其子类将自动具有该注解。 比如如果把标有Inherited注解的自定义的注解标注在类级别上子类则可以继承父类类级别的注解 实际应用中使用较少
Inherited 源码 从源码看该注解没有任何属性。 package java.lang.annotation;Documented
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.ANNOTATION_TYPE)
public interface Inherited {
}
7. 通过反射获取到注解信息
想要让反射可以读取到注解中的信息则该反射中的元注解必须是 Retention(RetentionPolicy.RUNTIME) 才行。
举例 这里我们使用反射读取到 fun() 方法中的 注解中的 value 属性值
注解
package blogs.blog10;import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;Retention(RetentionPolicy.RUNTIME) // 生命周期在运行期才可以被反射读取到
public interface MyAnnotation {String value() default Tom;}
package blogs.blog10;import java.lang.reflect.Method;public class AnnotationTest {public static void main(String[] args) {Method method null;try {// 获取类加载器类对象Class clazz Class.forName(blogs.blog10.AnnotationTest); // 全类路径名// 获取 fun()方法method clazz.getDeclaredMethod(fun);} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();}// 判断该方法是否存在该注解存在才读取该注解上的属性值if(method.isAnnotationPresent(MyAnnotation.class)) {// 获取该注解对象MyAnnotation annotation method.getAnnotation(MyAnnotation.class);// // 获取该注解的属性值就像对象.属性一样String value annotation.value();System.out.println(value);}}MyAnnotation(lihua)public void fun() {int num 0;}} 8. 总结:
设计注解类型时必须考虑该类型注解的基数。现在可以使用注解零次一次或者如果注解的类型被标记为 Repeatable 多次。也可以通过使用 Target 元注解来限制注解类型的使用位置。例如您可以创建只能在方法和字段上使用的可重复注解类型。重要的是仔细设计注解类型以确保使用注解的程序员发现它尽可能灵活和强大。注解的作用减少程序中的错误提高程序员的开发效率。以及框架上的运用。注意注解中的属性必须赋值不然编译无法通过除非该属性设置了默认值信息建议注解中的属性设置上默认值。当注解中只有一个属性并且该属性名为 value 则在赋值上可以省略属性名。注解多个值上的赋值以及数组类型的属性值的赋值。元注解修饰注解上的注解特别掌握TargetRetention 这两个元注解其中的属性值上的赋值的意义。
9. 最后 限于自身水平其中存在的错误希望大家给予指教韩信点兵——多多益善 。谢谢大家江湖再见后会有期