java中的注解
1、注解概述
@Ovrride:用来修饰方法,表示该方法是重写父类的方法,如果不是,就会报错
注解(Annotation):也叫元数据,一种代码级别的说明,它是JDK1.5及以后版本引入的一个特性
它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明
JDK1.5之后的新特性
说明程序的
注解和注释:
注解:用来说明程序,给计算机看的
注释:用来对程序进行说明性的文字,给程序员看的
Java中常见的几个注解:
@Override
@Deprecated
@SuppressWarnings
@FunctionalInterface
@Override
用于指定方法是否重写父类的方法,只能修饰方法,不能够修饰其它元素
单独来看,可能丝毫看不出程序中@Override有何作用,因为他的作用是告诉编译器检查这个方法,保证父类要包含一个被该方法重写的方法
@Deprecated
用于表示某个程序元素(类、方法等)已过时,当其它程序使用已过时的类、方法时,编译器将会给出警告
Java 9 为@Deprecated增加了两个属性:
since:该String类型的属性指定该API从哪个版本被标记为过时
forRemoval:该boolean类型的属性指定该API在将来事发后会被删除
@SuppressWarnings
指示被该注解修饰的程序元素(以及该程序元素中的所有子元素)取消显示指定的编译器警告
使用注解来关闭编译器警告时,一定要在括号里使用 name = value 的形式为该注解的成员变量设置值
@SuppressWarnings(value = "all")
@FunctionalInterface
Java 8 新增的,只能用来修饰接口,表示该接口是一个函数式接口
函数式接口:接口中有且仅有一个抽象方法
Lambda表达式的使用前提:接口中有且仅有一个抽象方法
参考代码:
package com.itheima_01;
public class Fu {
public void show(){
System.out.println("fu show");
}
@Deprecated
public void method(){
System.out.println("fu method");
}
}
package com.itheima_01;
public class Zi extends Fu{
@Override
public void show(){
System.out.println("zi show");
}
}
package com.itheima_01;
@FunctionalInterface
public interface Inter {
void show();
// void show2();
}
package com.itheima_01;
import java.util.ArrayList;
import java.util.List;
/*
测试类
*/
//@SuppressWarnings(value = "all") 用于取消编译器检查
public class Test {
public static void main(String[] args){
Fu f = new Fu();
f.method(); //被标记的方法在调用处显示过时
// @SuppressWarnings(value = "all")
List<String> list = new ArrayList();
}
}
2、元注解:
对注解进行注解。也就是写在注解上面的注解。
两个常用的元注解:
@Retention
@Target
可以通过跟进@Deprecated、@Override查看
@Retention(表示注解存在的位置:class文件、源代码)
只能用于修饰注解定义,用于指定被修饰的注解可以保留多长时间
包含了一个RetentionPolicy类型的value成员变量,所以使用的@Retention时必须为该value成员变量指定
@Retention中可以使用的值定义在RetentionPocily中,常用值如下:
RetentionPolicy.CLASS:编译器把注解记录在class文件中,当运行Java程序时,JVM不可获取注解信息,这是默认值
RetentionPolicy.RUNTIME:编译器把注解记录在class文件中,当运行Java程序时,JVM也可以获取注解信息,开发中常用
RetentionPolicy.SOURCE:注解只保留在源代码中,编译器直接丢弃这种注解
@Target(表示注解修饰的对象如:接口、类、方法等等等)
只能用于修饰注解定义,用于指定被修饰的注解能用于修饰哪些程序单元,包含一个名为value的成员变量
@Target中可以使用的值定义在ElementType中,常用值如下:
@Target(ElementType.TYPE):可以用于接口、类、枚举、注解
@Target(ElementType.FIELD):可以用于属性字段、枚举的常量
@Target(ElementType.METHOD):可以用于方法
@Target(ElementType.PARAMETER):可以用于方法参数
@Target(ElementType.CONSTRUCTOR):可以用于构造函数
@Target(ElementType.LOCAL_VARIABLE):可以用于局部变量
3、自定义注解:
定义格式:
元注解
public @interface 注解名称{
属性列表;
}
注解的本质:
public Interface MyAnnotation extends Annotation{}
是一个接口,该接口默认继承Annotation接口
既然是接口,那么内部定义的内容,就是接口中可以定义的内容
注解的属性:
属性:接口中的抽象方法
格式:返回值类型 属性名()[default 默认值]
注解属性类型可以有以下列出的类型:
基本数据类型
String
枚举类型
注解类型
Class类型
以上类型的一维数组类型
参考代码:
package com.itheima_02;
//@interface 表示定义一个注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
/*
无参无返回值的方法:void show();
无参带返回值的方法:String show();
注解中定义属性也是这样的格式:
返回值类型 属性名()
*/
//定义两个属性
String name() default "fqy";
int age();
}
4、注解的使用和解析:
使用注解:
如果注解有多个属性,则可以在注解括号中用 “,” 号隔开分别给对应的属性赋值
如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值
如果只有一个属性需要赋值,并且属性的名称时value,则value可以省略,直接定义值即可
数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略
参考代码:
package com.itheima_03;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
// String name() default "zs"; //表示默认值为zs,使用时可以不用给此属性赋值
//
// int age();
// String value(); //当注解中只有一个属性需要赋值,且此属性为value时可以直接定义值
String[] names();
}
package com.itheima_03;
//@MyAnnotation(name = "张三", age = 36) //注解的多个属性使用,隔开
//@MyAnnotation(age = 36)
//@MyAnnotation("好好学习天天向上") //@MyAnnotation(value = "好好学习天天向上")
//@MyAnnotation(names = {"张三", "李四", "王五", "赵六"})
@MyAnnotation(names = "张三") //属性为数组时,只有一个值大括号可以省略
public class MyAnnotationTest {
}
解析注解:
获取字节码文件对象,获取谁的呢?谁使用了注解,就是获取谁的
Class
获取字节码对象上的注解信息
MyAnnotation annotation = c.getAnnotation(MyAnnotation.class);
解析注解
String name = annotation.name();
int age = annotation.age();
参考代码:
package com.ithiema_04;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
String name() default "zs"; //表示默认值为zs,使用时可以不用给此属性赋值
int age();
}
package com.ithiema_04;
//@MyAnnotation(age = 36)
@MyAnnotation(name = "张三", age = 30)
public class MyAnnotationTest {
public static void main(String[] args){
//!!!通过反射解析注解
//先获取使用注解类的class文件
//再通过一个方法传入使用注解的class文件,来创建对应的注解对象,在获取其属性对应的值
//获取字节码文件对象,谁使用了注解就获取谁的字节码文件
Class<MyAnnotationTest> c = MyAnnotationTest.class;
//通过字节码文件对象获取注解信息
MyAnnotation myAnnotation = c.getAnnotation(MyAnnotation.class);
//通过注解的属性获取对应的值
String name = myAnnotation.name();
int age = myAnnotation.age();
System.out.println(name + "," + age);
}
}
案例:框架通用技术:
需求:通过注解,运行指定类中的指定方法
参考代码:
package com.itheima_05;
public class Student {
public void study(){
System.out.println("好好学习天天向上");
}
}
package com.itheima_05;
public class Teacher {
public void teach(){
System.out.println("用爱成就学员");
}
}
package com.itheima_05;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/*
定义一个注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
String className();
String methodName();
}
package com.itheima_05;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/*
通过注解来运行指定类中的指定方法
*/
//运行某个类中的某个方法,只需要来修改这里的内容即可
//@MyAnnotation(className="com.itheima_05.Student",methodName="study")
@MyAnnotation(className="com.itheima_05.Teacher",methodName="teach")
public class MyAnnotationTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//!!!通过注解来获取类名和方法名
//获取class文件对象,谁使用了注解就获取谁的
Class<MyAnnotationTest> myAnnotationTestClass = MyAnnotationTest.class;
//通过字节码文件对象创建注解对象
MyAnnotation myAnnotation = myAnnotationTestClass.getAnnotation(MyAnnotation.class);
//通过注解对象获取属性值
String className = myAnnotation.className();
String methodName = myAnnotation.methodName();
//以下部分为反射机制:即通过class字节码文件创建Class对象,再通过Class对象创建实例化对象,在调用其中的方法
//通过类名反射得到Class对象
Class<?> c = Class.forName(className); //com.ithiema_06.Student
//通过Class对象创建一个对象
Constructor<?> con = c.getConstructor();
Object obj = con.newInstance();
//通过Class得到方法
Method m = c.getMethod(methodName);//study
//调用方法
m.invoke(obj);
}
}
标签:38,Java,java,class,import,注解,MyAnnotation,public
From: https://www.cnblogs.com/fragmentary/p/17032195.html