Java学习之注解

注解:Java SE 5.0 版本中开始引入的概念,注解和class,interface一样也是一种Java类型,声明注解是通过@interface来声明的.

public @interface TestAnnotation {
}

注解的功能:主要是起到标签说明的作用,可以作用与类名,方法,成员变量,参数,私有变量等.但是它不影响所注解部分的代码功能.

那它存在的意义是什么,一个是编译器管理使用,一个是运行期通过反射获取注解,进行注解说明要操作的其他业务处理

注解是一系列元数据,它提供数据用来解释程序代码,但是注解并非是所解释的代码本身的一部分。注解对于代码的运行效果没有直接影响。

注解有许多用处,主要如下: 
- 提供信息给编译器: 编译器可以利用注解来探测错误和警告信息 
- 编译阶段时的处理: 软件工具可以用来利用注解信息来生成代码、Html文档或者做其它相应处理。 
- 运行时的处理: 某些注解可以在程序运行的时候接受代码的提取


对于注解首先我们要知道它是干嘛的,从上面我们基本也了解了,其次我们自己如何定义使用它,

在自己定义的时候我们得知道它的格式,上面已说,其次得知道元注解,这个是用来说明注解的基本使用规则的.

该博客写的很详细:https://blog.csdn.net/briblue/article/details/73824058

元注解:有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。下面来介绍:

@Retention

Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。

它的取值如下: 
- RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。 
- RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。 
- RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

我们可以这样的方式来加深理解,@Retention 去给一张标签解释的时候,它指定了这张标签张贴的时间。@Retention 相当于给一张标签上面盖了一张时间戳,时间戳指明了标签张贴的时间周期。

@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
}

上面的代码中,我们指定 TestAnnotation 可以在程序运行周期被获取到,因此它的生命周期非常的长。

@Documented

顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。

@Target

Target 是目标的意思,@Target 指定了注解运用的地方。

你可以这样理解,当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。

类比到标签,原本标签是你想张贴到哪个地方就到哪个地方,但是因为 @Target 的存在,它张贴的地方就非常具体了,比如只能张贴到方法上、类上、方法参数上等等。@Target 有下面的取值

  • ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
  • ElementType.CONSTRUCTOR 可以给构造方法进行注解
  • ElementType.FIELD 可以给属性进行注解
  • ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
  • ElementType.METHOD 可以给方法进行注解
  • ElementType.PACKAGE 可以给一个包进行注解
  • ElementType.PARAMETER 可以给一个方法内的参数进行注解
  • ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

@Inherited

Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。 
说的比较抽象。代码来解释。

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}


@Test
public class A {}


public class B extends A {}

注解 Test 被 @Inherited 修饰,之后类 A 被 Test 注解,类 B 继承 A,类 B 也拥有 Test 这个注解。

可以这样理解:

老子非常有钱,所以人们给他贴了一张标签叫做富豪。

老子的儿子长大后,只要没有和老子断绝父子关系,虽然别人没有给他贴标签,但是他自然也是富豪。

老子的孙子长大了,自然也是富豪。

这就是人们口中戏称的富一代,富二代,富三代。虽然叫法不同,好像好多个标签,但其实事情的本质也就是他们有一张共同的标签,也就是老子身上的那张富豪的标签。

@Repeatable

Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。

什么样的注解会多次应用呢?通常是注解的值可以同时取多个。

举个例子,一个人他既是程序员又是产品经理,同时他还是个画家。


@interface Persons {
    Person[]  value();
}


@Repeatable(Persons.class)
@interface Person{
    String role default "";
}


@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{

}

注意上面的代码,@Repeatable 注解了 Person。而 @Repeatable 后面括号中的类相当于一个容器注解。

什么是容器注解呢?就是用来存放其它注解的地方。它本身也是一个注解。

我们再看看代码中的相关容器注解。

@interface Persons {
    Person[]  value();
}

按照规定,它里面必须要有一个 value 的属性,属性类型是一个被 @Repeatable 注解过的注解数组,注意它是数组。

如果不好理解的话,可以这样理解。Persons 是一张总的标签,上面贴满了 Person 这种同类型但内容不一样的标签。把 Persons 给一个 SuperMan 贴上,相当于同时给他贴了程序员、产品经理、画家的标签。

我们可能对于 @Person(role=”PM”) 括号里面的内容感兴趣,它其实就是给 Person 这个注解的 role 属性赋值为 PM ,大家不明白正常,马上就讲到注解的属性这一块。

了解到元注解后,我们就可以通过元注解来给自定义的注解进行注解说明使用了

举例:spring的service注解:

@Target({ java.lang.annotation.ElementType.TYPE }):说明该注解可以给一个类型进行注解,比如类、接口、枚举
@Retention(RetentionPolicy.RUNTIME):说明该注解在运行时可以被使用,有效
@Documented:说明该注解在Javadoc中被说明
@Component:该注解是spring框架的注解不是元注解,但该注解的@Target类型是ElementType.TYPE,所以它可以注解一个类型包括注解在其他注解上

@Target({ java.lang.annotation.ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
	public abstract String value();
}

学注解一是要会用Java中已经有的注解,而是根据业务需求自定义注解.现在好多框架都支持使用注解,自己在用的spring框架中注解用的就比较多.自定义注解好多都是在运行中可以使用的.自己在工作做也可以自定义框架使用.

自己定义一个可以给属性定义的注解,但该类的实体类字段为空时给它设定初始值

该自定义注解:@Retention(RetentionPolicy.RUNTIME)和@Target({ElementType.FIELD})是最主要的,另外两个可以不用

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target({ElementType.FIELD})
@Inherited
public @interface NameTation {
	int value() default 1;//成员变量在该案例中是没有使用的
	Class Link();//成员变量在该案例中是没有使用的
	Type type();//成员变量
}
定义实体类:
package app.annotation;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;

public class Person {
	
	@NameTation(value=7,Link=Person.class,type=Type.STRING)
	String name;
	@NameTation(value=7,Link=Person.class,type=Type.INT)
	int age;
	@NameTation(value=7,Link=Person.class,type=Type.CHAR)
	char sex;
	@NameTation(value=7,Link=Person.class,type=Type.DOUBLE)
	double height;
	@NameTation(value=7,Link=Person.class,type=Type.STRING)
	String interstValue;
	@NameTation(value=7,Link=Person.class,type=Type.OBJECT)
	Object obj;
	@NameTation(value=7,Link=Person.class,type=Type.DATE)
	Date date;
	@NameTation(value=7,Link=Person.class,type=Type.BOOLEAN)
	boolean bool;
	
	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 char getSex() {
		return sex;
	}

	public void setSex(char sex) {
		this.sex = sex;
	}

	public double getHeight() {
		return height;
	}

	public void setHeight(double height) {
		this.height = height;
	}

	

	public String getInterstValue() {
		return interstValue;
	}

	public void setInterstValue(String interstValue) {
		this.interstValue = interstValue;
	}

	public Object getObj() {
		return obj;
	}

	public void setObj(Object obj) {
		this.obj = obj;
	}

	public Date getDate() {
		return date;
	}

	public void setDate(Date date) {
		this.date = date;
	}

	public void taget(){
		System.out.println("woshi fanfa");
	}
}

枚举类:

public enum Type {
	STRING(1),INT(1),DOUBLE(1),CHAR(1),DATE(1),
	FLOAT(1),BYTE(1),SHORT(1),LONG(1),BOOLEAN(1),OBJECT(1);
	
	private int type;
	Type(int type){
		this.type=type;
	}
	public int getType() {
		return type;
	}
	public void setType(int type) {
		this.type = type;
	}
	
	public static Object charge(Type t){
		switch (t) {
		case STRING:
			return "哈哈哈";
		case INT:
			return 1;
		case DOUBLE:
			return 1.0;
		case CHAR:
			return '1';
		case DATE:
			return new Date();
		case FLOAT:
			return 1f;
		case BYTE:
			return 1;
		case SHORT:
			return 1;
		case BOOLEAN:
			return false;	
		case LONG:
			return 1;
		default:
			return new Object();
		}
	}
	
}

测试类使用:

public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InstantiationException {
		Class cls=Person.class;//通过反射获取到class
		Person newInstance = cls.newInstance();//用class新建一个对象
		newInstance.setName("Lily");//赋值
		
		Field[] fields = cls.getDeclaredFields();//获取class的所有字段
		for(Field field:fields){
			Object object = field.get(newInstance);//获取该字段在对象中的值
			NameTation annotation = field.getAnnotation(NameTation.class);
			boolean annotationPresent = field.isAnnotationPresent(NameTation.class);
//判断是否为空且是否该字段被注解			if(annotationPresent && annotation!=null&&object==null){
				Object charge = Type.charge(annotation.type());//校验该字段的类型并返回相应的初始值
				field.set(newInstance, charge);//给字段赋值
				System.out.println("name:"+field.getName()+"------"+charge);
			}else{
				System.out.println("不为空"+field.getName()+object);
			}
		}
		









你可能感兴趣的:(Java学习之注解)