1、概述
2、内置注解
---2.1Override注解
---2.2Deprecated注解
3、元注解
---3.1关于Target注解
---3.2关于Retention注解
4、注解中定义属性
5、反射注解
6、通过反射获取注解对象属性的值
7、注解在开发中的作用
更多关于注解见:
链接一
链接二
概述
1、注解:Annotation是一种引用数据类型。编译之后也是生成xx.class文件。
2、语法格式为:
[修饰符列表] @interface 注解类型名{}
3、注解怎么使用?
注解使用时的语法格式是:@注解类型名
Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。(默认情况下,注解可以出现在任意位置。)
4、例:
@DemoAnno
public class Demo {
@DemoAnno
private int no;
@DemoAnno
public Demo() {
}
@DemoAnno
private void m(){
@DemoAnno
int a = 1;
}
}
@DemoAnno
interface MyInterface{
}
@DemoAnno
enum S {
ANN
}
@DemoA
public @interface DemoAnno {
}
5、一些内置注解
Deprecated
注释@Deprecated的程序元素是程序员不鼓励使用的程序元素,通常是因为它是危险的,或者因为存在更好的替代方法。
FunctionalInterface
使用的信息注释类型,以指示在接口类型声明旨在是一个 功能接口由Java语言规范所定义的。
Override
表示方法声明旨在覆盖超类型中的方法声明。
SafeVarargs
程序员断言注释方法或构造函数的正文不会对其varargs参数执行潜在的不安全操作。
SuppressWarnings
表示在注释元素(以及注释元素中包含的所有程序元素)中应该抑制命名的编译器警告。
内置注解
Override注解
1、源代码:
public @interface Override {}
2、是一个标识性注解,给编译器做参考。
方法上有这个注解的时候,编译器会自动检查该方法是否重写了父类的方法。如果没有重写会报错。这个注解只是在编译阶段起作用,和运行期无关。
3、只能注解方法,因为被Target限制了:
@Target(ElementType.METHOD)
Deprecated注解
1、被其标识后,表示被标识的元素已过时,告知程序员已过时,有更好的方案存在。
2、图例(其中过时的方法会加横杠):
运行后:
但是会有警告:
元注解
- 概述
1、用来标注“注解类型”的“注解”,称为元注解。
2、常见元注解:
@Retention
@Target
关于Target注解
1、Target注解用来标注“被标注的注解”可以出现在哪些位置上。
2、@Target(ElementType.METHOD)
表示“被标注的注解“只能出现在方法上。
关于Retention注解
1、Retention注解用来标注“被标注的注解”最终保存在哪里。
2、@Retention(RetentionPolicy.SOURCE)
表示该注解只被保留在java源文件中。
@Retention(RetentionPolicy.CLASS)
表示该注解被保存在class文件中
@Retention(RetentionPolicy.RUNTIME)
表示该注解被保存在class文件中,并且可以被反射机制所读取。
注解中定义属性
- 属性类型
属性的类型可以是:byte、short、int、long、float、double、boolean、char、string、class、枚举类型,以及它们的每一种的数组形式。 - 代码示例
public @interface DemoAnno {
//定义name属性
String name();
//定义age属性
int age();
//定义性别(指定属性的默认值)
String sex() default "男";
}
public class Demo {
/*报错的原因:注解中有属性,没有给属性赋值。
* (除非该属性使用default指定了默认值)*/
/*@DemoAnno()
public void doSome(){ }*/
//@DemoAnno(属性名=属性值,属性名=属性值...)
@DemoAnno(name = "zhangsan",age = 1)
public void doSome(){
}
}
- 属性是value时可以省略
1、限制条件:有且只有一个属性名叫value。
2、代码示例:
public @interface DemoAnno {
//定义value属性
String value();
}
public class Demo {
@DemoAnno(value = "v")
public void doSome(){
}
//省略了“value = ”
@DemoAnno("vv")
public void doOther(){
}
}
3、不止有value一个属性时:
public @interface DemoAnno {
//定义value属性
String value();
//再加一个属性
String name();
}
public class Demo {
//此时就不能省略value
@DemoAnno(value = "v", name = "zhangsan")
public void doSome(){
}
}
- 属性是数组时
public enum Season {
SPRING, SUMMER, AUTUMN, WINTER
}
public @interface DemoAnno {
String name();
String[] hobby();
//枚举数组
Season[] seasonArr();
}
public class Demo {
//数组中只有一个元素时,大括号可以省略
@DemoAnno(name = "v",
hobby = "zhangsan",
seasonArr = Season.SUMMER)
public void doSome(){
}
@DemoAnno(name = "v",
hobby = {"111@qq.com","222@qq.com"},
seasonArr = {Season.SPRING, Season.AUTUMN})
public void doOther(){
}
}
反射注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//该注解只能标注类、方法
@Target({ElementType.TYPE, ElementType.METHOD})
//该注解可以被反射
@Retention(RetentionPolicy.RUNTIME)
public @interface DemoAnno {
String value() default "zhangsan";
}
@DemoAnno("lisi")
public class Demo {
@DemoAnno
public void doSome(){
int i;
}
}
public class DemoTest {
public static void main(String[] args) throws Exception{
Class c = Class.forName("Demo");
/*判断类上面是否有@DemoAnno
* 输出:true*/
//System.out.println(c.isAnnotationPresent(DemoAnno.class));
if (c.isAnnotationPresent(DemoAnno.class)){
//获取该注解对象
DemoAnno demoAnno = (DemoAnno)c.getAnnotation(DemoAnno.class);
System.out.println("类上的注解对象是:"+ demoAnno);
//获取注解对象的属性
String s = demoAnno.value();
System.out.println(s);
}
}
}
输出:
通过反射获取注解对象属性的值
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DemoAnno {
String username();
String password();
}
import java.lang.reflect.Method;
public class Demo {
@DemoAnno(username = "admin", password = "123")
public void doSome(){
}
public static void main(String[] args) throws Exception{
//获取Demo的doSome()方法上面的注解信息
Class c = Class.forName("Demo");
//获取doSome()方法
Method doSomeMethod = c.getDeclaredMethod("doSome");
//判断该方法上是否存在这个注解
if (doSomeMethod.isAnnotationPresent(DemoAnno.class)){
DemoAnno demoAnno = doSomeMethod.getAnnotation(DemoAnno.class);
System.out.println(demoAnno.username());
System.out.println(demoAnno.password());
}
}
}
输出:
注解在开发中的作用
1、假如以这样一个需求:
有一个注解叫:@DemoAnno。这个注解只能出现在类上面,当这个类上有这个注解的时候,要求这个类中必须有一个int类型的id属性。如果没有这个属性就报异常,如果有这个属性则正常执行。
2、代码示例:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DemoAnno {
}
@DemoAnno()
public class Demo {
//int id;
String name;
String psw;
}
/*自定义异常*/
public class No_Id_Exception extends RuntimeException{
public No_Id_Exception() {
}
public No_Id_Exception(String message) {
super(message);
}
}
import java.lang.reflect.Field;
public class DemoTest {
public static void main(String[] args) throws Exception{
Class demoClass = Class.forName("Demo");
//布尔标记
boolean isOk = false;
if (demoClass.isAnnotationPresent(DemoAnno.class)){
/*有注解的话,要求必须存在int类型的id属性*/
//获取类的属性
Field[] fields = demoClass.getDeclaredFields();
for (Field field:fields) {
if ("id".equals(field.getName())
&& "int".equals(
field.getType().getSimpleName())){
//合法
isOk = true;
break;
}
}
if (!isOk) {
throw new No_Id_Exception(
"没有int类型的id属性");
}
}
}
}
有int id时(无异常):
没有int id时: