注解
注解定义
Annotation (注解) 是 Java5 开始引入的新特性,可以看作是一种特殊的注释,主要用于修饰类、方法或者变量,提供某些信息供程序在编译或者运行时使用。但是注解并不是所装饰代码的一部分,它对代码的运行效果没有直接影响,由编译器决定该执行哪些操作。
Java所有的注解,默认实现Annotation接口
package java.lang.annotation;
public interface Annotation {
boolean equals(Object obj);
int hashCode(); String toString();
Class<? extends Annotation> annotationType();
}
元注解
- 元注解是注解的注解,是一张特殊的标签,即标签的标签。
- 元注解是用于给其他普通标签进行解释说明的。
- 元标签有:@Retention, @Documented, @Targrt, @Inherited, @Repeatable 共5种。
@Retention
注解的生命周期有 3 种策略,定义在 RetentionPolicy 枚举中。
- SOURCE:在源文件中有效,在编译阶段被编译器丢弃。
- CLASS:注解只被保留到编译进行的时,在编译器生成的字节码文件中有效,但在运行时会被处理类文件的 JVM 丢弃。
- RUNTIME:注解可以保留到程序运行的时候,在运行时有效。这也是注解生命周期中最常用的一种策略,它允许程序通过反射的方式访问注解,并根据注解的定义执行相应的代码。
@Documented
该注解将被包含在javadoc中
@Targrt
注解标记另一个注解,以限制可以应用注解的 Java 元素类型。目标注解指定以下元素类型之一作为其值:
- ElementType.ANNOTATION_TYPE 可以应用于注解类型。
- ElementType.CONSTRUCTOR 可以应用于构造函数。
- ElementType.FIELD 可以应用于字段或属性。
- ElementType.LOCAL_VARIABLE 可以应用于局部变量。
- ElementType.METHOD 可以应用于方法级注解。
- ElementType.PACKAGE 可以应用于包声明。
- ElementType.PARAMETER 可以应用于方法的参数。
- ElementType.TYPE 可以应用于类的任何元素。
@Inherited
子类可以继承父类中的该注解
@Repeatable
用于标注可重复的注解。
如下所示:
Logme
package dynamic.annotation;
import java.lang.annotation.*;
/**
* @author yangmiao
*/
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Logme {
String value() default "";
Class<?> clz();
}
反射
参考文档:
通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。
优缺点
缺点:
- 破坏封装:由于反射允许访问私有字段和私有方法,所以可能会破坏封装而导致安全问题。
- 性能开销:由于反射涉及到动态解析,因此无法执行 Java 虚拟机优化,再加上反射的写法的确要复杂得多,所以性能要比“正射”差很多,在一些性能敏感的程序中应该避免使用反射。
优点:
- 可以实现动态创建对象和编译,体现出很大的灵活性。
应用场景
- 开发通用框架:像 Spring,为了保持通用性,通过配置文件来加载不同的对象,调用不同的方法。
- 动态代理:在面向切面编程中,需要拦截特定的方法,就会选择动态代理的方式,而动态代理的底层技术就是反射。
- 注解:注解本身只是起到一个标记符的作用,它需要利用发射机制,根据标记符去执行特定的行为。
创建对象
- 使用newInstance()方法。
- 反射获取构造函数,使用构造函数的方式创建对象。用 Constructor 对象的 newInstance() 方法
Class 对象提供了以下方法来获取构造方法 Constructor 对象:
- getConstructor():返回反射类的特定 public 构造方法,可以传递参数,参数为构造方法参数对应 Class 对象;缺省的时候返回默认构造方法。
- getDeclaredConstructor():返回反射类的特定构造方法,不限定于 public 的。
- getConstructors():返回类的所有 public 构造方法。
- getDeclaredConstructors():返回类的所有构造方法,不限定于 public 的。
属性操作
- getField(String name) 获取某个public类型的属性
- getFields() 获取所有的public类型的属性
- getDeclaredField(String name) 获取某个属性对象
- getDeclaredFields() 获取所有的属性对象
函数操作
- getMethod(String name, Class…<?> parameterTypes) 获取与参数类型匹配的public类型的函数
- getMethods() 获取所有的public类型的函数(包含继承的函数)
- getDeclaredMethod(String name, Class…<?> parameterTypes) 获取与参数类型匹配的所有函数
- getDeclaredMethods() 获取所有的函数
Demo
User
package dynamic.annotation;
/**
* @Author: Yangmiao
* @Date: 2022/10/21 19:48
* @Desc:
*/
@Logme(value = "print me",clz = User.class)
public class User {
private String userName;
private String password;
public void setPassword(String password) {
this.password = password;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public String getUserName() {
return userName;
}
private String addStr(String userName,String password){
return userName+"_"+password;
}
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", password='" + password + '\'' +
'}';
}
}
TestAnnotation
package dynamic.annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @Author: Yangmiao
* @Date: 2022/10/21 19:50
* @Desc:
*/
public class TestAnnotation {
public static void main(String[] args) {
User user = new User();
user.setPassword("1323");
user.setUserName("yyyy");
Class<? extends User> userClass = user.getClass();
Logme logme = userClass.getAnnotation(Logme.class);
String value = logme.value();
Class<?> clz = logme.clz();
System.out.println("value: "+value+" clz: "+clz);
System.out.println("constructor: "+userClass.getConstructors());
for (Field field:userClass.getDeclaredFields()) {
System.out.println("field: "+field);
}
try {
Class<?> userTemp = Class.forName("dynamic.annotation.User");
// for (Method method:userClass.getMethods()) {
// System.out.println("method: "+method);
// }
System.out.println("*********reflect**********");
Method addStr = userClass.getDeclaredMethod("addStr", String.class, String.class);
addStr.setAccessible(true);
Object invoke = addStr.invoke(userClass.newInstance(), "yymm", "haha");
System.out.println("addStr: "+invoke.toString());
System.out.println("*********stream**********");
Arrays.stream(userTemp.getDeclaredFields()).forEach(System.out::println);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
测试结果:
/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/bin/java -Dvisualvm.id=119516826323250 -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=56814:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/charsets.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/ext/cldrdata.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/ext/dnsns.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/ext/jaccess.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/ext/jfxrt.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/ext/localedata.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/ext/nashorn.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/ext/sunec.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/ext/sunjce_provider.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/ext/sunpkcs11.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/ext/zipfs.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/jce.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/jfr.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/jfxswt.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/jsse.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/management-agent.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/resources.jar:/Users/yangmiao/Library/Java/JavaVirtualMachines/liberica-1.8.0_322/jre/lib/rt.jar:/Users/yangmiao/Documents/javaSource/codeme/target/classes dynamic.annotation.TestAnnotation
value: print me clz: class dynamic.annotation.User
constructor: [Ljava.lang.reflect.Constructor;@6e0be858
field: private java.lang.String dynamic.annotation.User.userName
field: private java.lang.String dynamic.annotation.User.password
*********reflect**********
addStr: yymm_haha
*********stream**********
private java.lang.String dynamic.annotation.User.userName
private java.lang.String dynamic.annotation.User.password
Process finished with exit code 0
欢迎大家关注个人微信公众号:一杯Java不加糖呢,不定期更新文章,谢谢🙏~