// 自定义注解
public @interface MyTest {
String aaa();
boolean bbb() default true;
String[] ccc();
}
// 方法部分
@MyTest(aaa = "Jack", ccc = {"Java", "HTML"})
public void run() {}
特殊属性名:value——如果注解中只有一个 value 属性,使用注解时,value 名称可以不写!
public @interface MyTest {
String value(); // 特殊属性
}
public @interface MyTest {
String value(); // 特殊属性
int age() default 23; // 当有默认值时候,可以不删除此行
}
@MyTest("Jack")
public void run() {}
@Target(ElemeElenntType.TYPE) | 作用:声明被修饰的注解只能在哪些位置使用 |
---|---|
TYPE | 类,接口 |
FIELD | 成员变量 |
METHOD | 成员方法 |
PARAMETER | 方法参数 |
CONSTRUCTOR | 构造器 |
LOCAL_VARIABLE | 局部变量 |
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ElemeElenntType.TYPE,ElementType.METHOD}) // 当前被修饰的注解只能用在类和成员方法上
public @interface MyTest {
}
@Retention(RetentionPolicy.RUNTIME) | 作用:声明注解的保留周期 |
---|---|
SOURCE | 只作用在源码阶段,字节码文件中不存在 |
CLASS(默认值) | 保留到字节码文件阶段,运行阶段不存在 |
RUNTIME(开发常用) | 一直保留到运行阶段 |
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 MyTest {
}
什么是注解的解析?
如何解析注解?
// 自定义注解
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 MyTest {
String value();
double aaa() default 100;
String[] bbb();
}
// 在类和方法上使用注解
@MyTest(value = "Jack", aaa = 99.8, bbb = {"Java", "HTML"})
public class Demo {
public static void main(String[] args) {}
@MyTest(value = "Tony", aaa = 88.6, bbb = {"java", "html"})
public void run() {}
}
// 解析类上的注解
import org.junit.Test;
import java.util.Arrays;
public class AnnotationTest {
@Test
public void parseClass() {
// 1. 先得到 Class 对象
Class c = Demo.class;
// 2. 解析类上的注解
// 判断这个类上是否包含了某个注解
if (c.isAnnotationPresent(MyTest.class)) {
MyTest myTest = (MyTest) c.getDeclaredAnnotation(MyTest.class);
System.out.println(myTest.value());
System.out.println(myTest.aaa());
System.out.println(Arrays.toString(myTest.bbb()));
}
}
}
/*
运行结果:
Jack
99.8
[Java, HTML]
*/
// 解析方法上的注解
import org.junit.Test;
import java.lang.reflect.Method;
import java.util.Arrays;
public class AnnotationTest {
@Test
public void parseMethod() throws Exception {
// 1. 先得到 Class 对象,然后通过 Class 对象获取方法对象
Class c = Demo.class;
Method m = c.getDeclaredMethod("run");
// 2. 解析方法上的注解
// 判断这个方法上是否包含了某个注解
if (m.isAnnotationPresent(MyTest.class)) {
MyTest myTest = (MyTest) m.getDeclaredAnnotation(MyTest.class);
System.out.println(myTest.value());
System.out.println(myTest.aaa());
System.out.println(Arrays.toString(myTest.bbb()));
}
}
}
/*
运行结果:
Tony
88.6
[java, html]
*/
案例:模拟 Junit 框架
// 需求:定义若干个方法,只要加了MyTest注解,就会触发该方法的执行
/* 分析:
1.定义一个自定义注解 MyTest,只能注解方法,存活范围是一直都在
2.定义若干个方法,部分方法加上 @MyTest 注解修饰,部分方法不加
3.模拟一个 Junit 程序,可以触发加了 @MyTest 注解的方法执行
*/
// 自定义注解部分
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 MyTest {}
// 模拟框架部分
import java.lang.reflect.Method;
public class AnnotationTest {
public void test1() {
System.out.println("===test1===");
}
@MyTest
public void test2() {
System.out.println("===test2===");
}
public void test3() {
System.out.println("===test3===");
}
@MyTest
public void test4() {
System.out.println("===test4===");
}
public static void main(String[] args) throws Exception {
AnnotationTest a = new AnnotationTest();
// 启动程序!
// 1. 得到 Class 对象
Class c = AnnotationTest.class;
// 2. 提取这个类中的全部成员方法
Method[] methods = c.getDeclaredMethods();
// 3. 遍历,获取到每个方法对象,看看其方法上是否存在 @MyTest 注解
// 如果存在,则触发该方法执行
for (Method method : methods) {
if (method.isAnnotationPresent(MyTest.class)) {
method.invoke(a); // 触发当前方法执行
}
}
}
}
/*
运行结果:
===test2===
===test4===
*/
// 创建一个明星类(前置工作)
// 明星(类)
public class Star implements Agent {
private String name;
public Star(String name) {
this.name = name;
}
// 唱歌方法
public String sing(String title) {
System.out.println(this.name + "正在唱" + title);
return "Think everyone!";
}
// 跳舞方法
public void dance() {
System.out.println(this.name + "正在跳舞");
}
}
// 创建一个代理人接口(前置工作)
// 代理人(接口)
public interface Agent {
String sing(String name);
void dance();
}
// 创建一个工具类,即:能制作出"代理人"的公司(前置工作)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
// 中介公司(类)
public class ProxyUtil {
// 创建代理对象的静态方法
public static Agent createProxy(Star sss) {
/*
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
参数一:用于指定一个类加载器
参数二:指定生成的代理长什么样子,也就是有哪些方法
参数三:用来指定生成的代理对象要干什么事情
*/
Agent starProxy = (Agent) Proxy.newProxyInstance(
ProxyUtil.class.getClassLoader(), // 参数一
new Class[]{Agent.class}, // 参数二
new InvocationHandler() { // 参数三
@Override // 回调方法
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 代理对象要做的事情,请在这里写代码
if (method.getName().equals("sing")) {
System.out.println("准备话筒,收钱20W");
} else if (method.getName().equals("dance")) {
System.out.println("准备场地,收钱99W");
}
return method.invoke(sss, args);
}
});
return starProxy; // 本静态方法的最后是————返回创建好的"代理对象"
}
}
// 调用工具类,让公司为某个明星对象去定制一个专属代理人(正式部分)
public class Test {
public static void main(String[] args) {
// 创建一个明星,叫"迈克尔-杰克逊"
Star star = new Star("Michael-Jackson");
// 为"迈克尔-杰克逊"创建一个代理人
Agent agent = ProxyUtil.createProxy(star);
System.out.println(agent.sing("新年好")); // 让代理人安排他唱歌
System.out.println("-----------------");
agent.dance(); // 让代理人安排他跳舞
}
}
/* 运行结果:
准备话筒,收钱20W
Michael-Jackson正在唱新年好
Think everyone!
-----------------
准备场地,收钱99W
Michael-Jackson正在跳舞
*/