“ Annotation中文意思就是注解的意思,在 Java 中注解是一个很重要的知识点,但是理解Annotation以及怎么运用,你是否真的明白?”
01
—
Annotation
在平时工作中,使用注解应该是很常见的事情。但是对于注解你是否真正的去了解呢?下面我们一起来看一下如何去使用注解。
注解有什么用?Java 注解用于为 Java 代码提供元数据。不知道大家对于这句话是否理解,什么叫为Java代码提供元数据,我在一篇博客上看到一个非常通俗的解释:标签。注解就是对于代码中某些鲜活个体的贴上去的一张标签,也就是将一些对象使用注解的时候,可以理解为该对象被贴上一个标签。
知道注解的作用之后,我们来看一下注解的定义和使用:
1.定义注解:注解通过@interface
关键字进行定义。
@interface AnnotationExample {
}
2.注解的使用:
@AnnotationExample()
public class StudyAnnotation {
}
这里我们就定义来一个空的注解,和使用注解的类,那么如何让注解生效呢?那就需要提到元注解了,元注解是一种基本的注解,它能够应用到其它的注解上面。意思就是元注解是使用在注解上面的,也就是在AnnotationExample上面使用。元注解有哪些 呢?
元注解有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。
那么这5种元注解如何使用呢?
@Retention
Retention是保留期的意思,它解释说明了这个注解的的存活时间。
它有3种可使用的值:
-RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它
将被丢弃忽视。
-RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到
JVM 中。
-RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入
到 JVM 中,所以在程序运行时可以获取到它们。
通常我们会使用RetentionPolicy.RUNTIME这样注解的存活时间最久
@Documented
它的作用是能够将注解中的元素包含到 Javadoc 中去。什么意思呢?它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容会因为此注解的信息内容不同而不同。
@Target
指定了注解运用的地方。你可以这样理解,当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。它有如下可选值
ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
ElementType.CONSTRUCTOR 可以给构造方法进行注解
ElementType.FIELD 可以给属性进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE 可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解
ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
@Inherited
Inherited 是继承的意思,什么意思呢?如果一个类使用了拥有Inherited的注解,如果它的子类没有被任何注解应用的话,那么这个子类就继承了该类的注解。
@Repeatable
Repeatable是可重复的意思。@Repeatable 是 Java1.8加进来的,所以算是一个新的特性。 换句话说就是,可以多次使用被Repeatable修饰的注解,一个人可以有很多身份,类也一样,通过注解要表示它多个身份的时候,我们就需要用Repeatable
@interface Persons {
Identity[] identity();
}
@Repeatable(Persons.class)
@interface Identity{
String identity default "";
}
@Identity(role="artist")
@Identity(role="coder")
@Identity(role="PM")
public class SuperMan{
}
到这里我们就已经大致的了解注解是什么,那么如何去使用注解呢?
02
—
注解的使用
我们通过一个实例来看如何运用注解吧(希望大家能发散思维去想如何运用注解,不只是停留在我所举的例子中)。
假如我有一个接口,而接口下面有两个实现类,我想通过注解实现在不同情况下去去调用这两个实现类(可以运用到策略模式上面)。
现在我们来定义一个注解
@interface AnnotationExample {
int Identity() default 0;
}
这个注解中Identity默认是0,现在我们要定义一个接口和两个实现类,同时在实
现类上加上这个注解
interface inter{
void printInfo();
}
@AnnotationExample(Identity = 1)
class interImp implements inter{
@Override
public void printInfo() {
System.out.println("欢迎大家关注每天学Java公众号,这里每天都有文章推送(应该每天都会有吧,嘿嘿)");
}
}
@AnnotationExample(Identity = -1)
class interImp1 implements inter{
@Override
public void printInfo() {
System.out.println("欢迎大家进入每天学Java小程序,这里每天都有题库更新(应该每天都会有吧,嘿嘿)");
}
}
注解定义了,接口也定义了,实现类也是使用了注解,那么接下来我们要做什么呢?
既然是根据注解来区别不同的实现类,那么首先我们要获取到这个注解下面有多少类使用类它(用到了反射)。关于API这里就不介绍了,大家私下去看,直接上代码。
首先说明一下,注解的API一般都是Class 对象作为参数,所以我们首先需要拿到class文件。
class MainTest2 {
//存放class 文件集合
private static List<Class<? extends inter>> list;
//获取类加载器
private ClassLoader classLoader =
getClass().getClassLoader();
//获取扫描的包下面所有的class文件
private File[] getResources() {
try {
//我这里 src 目录下没有建包,可以直接使用getResource("")
//如何有包,getResource(包名字.replace(".", "/"))
File file =
new File(classLoader.getResource("").toURI());
return file.listFiles(new FileFilter() {
public boolean accept(File pathname) {
//只取class文件
if (pathname.getName().endsWith(".class")) {//我们只扫描class文件
return true;
}
return false;
}
});
} catch (URISyntaxException e) {
throw new RuntimeException("未找到策略资源");
}
}
//拿到class文件后,我们要找到使用这个注解的实现类
public void getImpClass() throws ClassNotFoundException {
list = list = new ArrayList<Class<? extends inter>>();
File[] resources = getResources();
// System.out.println(resources.length);
//使用相同的加载器加载实现类的接口
Class<inter> interClass = (Class<inter>) classLoader.loadClass(inter.class.getName());
for (int i = 0; i < resources.length; i++) {
try {
//载入包下的类
Class<?> clazz = classLoader.loadClass(resources[i].getName().replace(".class", ""));
// System.out.println(i);
//判断是否是inter的实现类并且不是它本身,满足的话加入到策略列表
if (inter.class.isAssignableFrom(clazz) && clazz != interClass) {
// System.out.println(i);
list.add((Class<? extends inter>) clazz);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
//处理注解,我们传入一个实现类,返回它的注解
private static AnnotationExample handleAnnotation(Class<? extends inter> clazz) {
Annotation[] annotations = clazz.getAnnotations();
if (annotations == null || annotations.length == 0) {
return null;
}
for (int i = 0; i < annotations.length; i++) {
if (annotations[i] instanceof AnnotationExample) {
return (AnnotationExample) annotations[i];
}
}
return null;
}
//开始区分
public void ide() {
for (Class<? extends inter> claszz : list) {
AnnotationExample annotationExample = handleAnnotation(claszz);
System.out.println(annotationExample.Identity());
if (annotationExample.Identity() == 1) {
try {
claszz.newInstance().printInfo();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws ClassNotFoundException {
MainTest2 mainTest2 = new MainTest2();
mainTest2.getImpClass();
mainTest2.ide();
}
}
通过annotationExample.Identity() == 1这一行,我们可以把这个1作为参数进行传入,然后通过注解就可以获取到不同的实现类的实例,这样我们就能通过注解来区分不同的实现类,达到我们想要的目的。
今天小程序更细题库:进入小程序
1.什么是元数据(metadata)
2.什么是注解(Annotation)?
3.数据的加密模式?加密模式的顺序?
4.post和get以及get和load的区别?使用get应注意什么?
5.Java 类加载器都有哪些