Java注解(Annotation)学习


什么是注解

注解(Annotation)是从JDK5.0开始弓|入的新技术。

注解的作用

  • 不是程序本身,可以对程序作出解释。(这一点, 跟注释没什么区别)
  • 可以被其他程序(此如:编译器等)读取。(注解信息处理流程,是注解和注释的重大区别。如果没有注解信息处理流程,则注解毫无意义)

注解的格式

  • 注解是以"@注释名"在代码中存在的,还可以添加一些参数值,例如: @SuppressWarnings(value= "unchecked")

注解在哪里使用

  • 可以附加在package, class, method, field等上面,相当于给它们添加了额外的辅助信息,我们可以通过反射机制编程实现对这些元数据的访问。



内置注解

@Override

  • 定义在java.lang.Override中 ,此注解只适用于修辞方法,表示一个方法声明打算重写父类中的一个方法。
  • 不是重写时使用这个注解会报错,比如方法名字与父类定义的名字不相同时。

@Deprecated

  • 定义在java.lang.Deprecated中,此注解可用于修辞方法、属性、类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。

@SuppressWarnings

  • 定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息。
  • 与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数值都是已经定义好了的, 我们选择性的使用就好了,参数如下:
参数 说明
deprecation 使用了过时的类和方法的警告
unchecked 执行了未检查的转换时的警告,如使用集合时未指定泛型
fallthrough 当在switch语句使用时发生case穿透
path 在路径、源文件路径等中有不存在路径的警告
serial 当在可序列化的类上缺少serialVersionUID定义时的警告
finally 任何finally子句不能完成时的警告
all 关于以上所有情况的警告
  • 使用单个参数的用法:@SuppressWarnings("unchecked")
  • 使用多个参数的用法:@SuppressWarnings(value={"unchecked", " deprecation"})

测试代码

import java.util.ArrayList;
import java.util.List;

public class Demo01 /*extends Object*/{
	@Override
	public String toString() {
		return super.toString();
	}
	
	@Deprecated
	public static void text001(){
		System.out.println("text001");
	}
	
	public static void text002(){
		List list1 = new ArrayList();
		List list2 = new ArrayList();
	}
}




自定义注解

  • 使用@interface自定义注解时,自动继承 java.lang.annotation.Annotation接口

要点:

  • @interface用来声明一 个 注解,格式为:public @interface注解名{定义体}
  • 其中的每一个方法实际上是声明了一个配置参数。
  • 方法的名称就是参数的名称
  • 返回值类型就是参数的类型(返回值类型只能是基本类型、Class、 String、enum. )。
  • 可以通过default来声明参数的默认值。
  • 如果只有一个参数成员,一 般参数名为value

元注解

  • 元注解的作用就是负责注解其他注解。 Java定义了4个标准的meta-annotation类型,它们被用来提供对其它annotation类型作说明。
  • 这些类型和它们所支持的类在java.lang.annotation包中可以找到
    @Target
    @Retention
    @Documented
    @Inherited
    其中前两个比较常见,下面进行介绍。

@Target

  • 作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
  • 用法:@Target(value= ElementType. TYPE)

@Retention

  • 作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期。
取值 作用
SOURCE 在源文件中有效(源文件保留)
CLASS 在class文件中有效(class保留)
RUNTIME 在运行时有效(运行时保留)

代码实现:

自定义注解类1:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value={ElementType.METHOD,ElementType.TYPE})//描述注解的使用范围
@Retention(RetentionPolicy.RUNTIME) //描述注解的生命周期
public @interface MyAnnotation01 {
	
	//这不是方法,注解的参数名都是带括号的
	//default用于声明参数的默认值
	String studentName() default "";
	int age() default 0;
	int id() default -1;
	String[] schools() default {"清华大学","北京大学"};
}

自定义注解类2

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value={ElementType.METHOD,ElementType.TYPE})//描述注解的使用范围
@Retention(RetentionPolicy.RUNTIME) //描述注解的生命周期
public @interface MyAnnotation02 {
	String value();
}

测试代码:

@MyAnnotation01
public class Demo02 {
	
	@MyAnnotation01(age=19,studentName="小高", id=1001,
			schools={"复旦大学","南开大学"})
	public void test(){
	}
	
	@MyAnnotation02(value="abc")
	//@MyAnnotation02("abc")  只有一个参数时,这样写也可以
	public void test2(){
	}
}



通过反射机制读取注解

  注解是元素的说明,但是如果注解仅仅是对元素进行说明,不能让其他程序运行时读取的话,这样和注释是没有区别的。这样注解就没有了意义。
  下面举一个例子体现读取注解的作用,我们常常将对象的信息存储在表中,一个表对应一个类,一条记录对应一个对象,一个列对应一个属性。
  我们用程序(一般用现成的框架,也可以自己写)将对象存储到表中时,需要生成SQL语句;这时,我们需要知道存储到哪一个表中,每一个属性对应哪一列,如果需要创建这个表,我们还需要知道列的属性和长度等等。
  以上我们需要的信息可以用注解声明,所以在存储对象信息时,我们就需要读取注解。这时,可以用到反射机制。

  下面模拟将sxtStudent类对象存储到数据库tb_student表中;共四步:

  1. 定义注解
  2. 在类中使用注解
  3. 编写读取注解的程序(也可以用框架),获得想要的信息
  4. 根据获得的表名和字段信息,拼出SQL语句,使用JDBC执行这个SQL,在数据库中生成相应的表或者是将数据添加到相应的表中。


定义注解:

声明表的注解:

package 注解;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/*
 * 此注解用于声明存放到哪一个表中
 */
@Target(value={ElementType.TYPE})//描述注解的使用范围
@Retention(RetentionPolicy.RUNTIME) //描述注解的生命周期
public @interface SxtTable {
	String value();
}

声明属性的注解:

package 注解;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/*
 * 此注解用于声明属性对应的列名,类型,长度
 */
@Target(value={ElementType.FIELD})//描述注解的使用范围
@Retention(RetentionPolicy.RUNTIME) //描述注解的生命周期
public @interface SxtField {
	String columnName();
	String type();
	int length();
}



在类中使用注解

package 注解;

@SxtTable("tb_student") 
public class sxtStudent {
	
	@SxtField(columnName="id", type="int", length=10)
	private int id;
	@SxtField(columnName="sname", type="varchar", length=10)
	private String studentName;
	@SxtField(columnName="age", type="int", length=3)
	private int age;
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public String getStudentName() {
		return studentName;
	}
	public void setStudentName(String studentName) {
		this.studentName = studentName;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	
}



编写读取注解的程序

package 注解;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;

/**
 * 使用反射读取注解的信息
 * @author Administrator
 *
 */
public class Demo03 {
	public static void main(String[] args) {
		//使用反射获取sxtStudent类  注解使用在那一个类就获取那一个类进行读取
		try {
			Class clazz = Class.forName("注解.sxtStudent");
			
			//获得类的所有有效注解
			Annotation[]  annotations = clazz.getAnnotations();
			for(Annotation an:annotations){
				System.out.println(an);
			}
			
			//获得类的指定的注解
			SxtTable st = (SxtTable) clazz.getAnnotation(SxtTable.class);
			System.out.println(st.value());
			
			//先通过反射获取类的studentName属性
			Field f = clazz.getDeclaredField("studentName");
			//在通过属性f获取它的注解
			SxtField sxtField = f.getAnnotation(SxtField.class);
			System.out.println(sxtField.columnName()+"--"+sxtField.type()+"--"+sxtField.length());
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}
}

猜你喜欢

转载自blog.csdn.net/HC199854/article/details/106626893
今日推荐