java注解与反射(非常详细, 带有很多样例)

打印 上一主题 下一主题

主题 902|帖子 902|积分 2706

下面是详细地讲解 Java 中的注解与反射,并提供了很多的示例来资助明白。
Java 注解(Annotations)

1. 注解的根本概念

注解(Annotation)是 Java 5 引入的一种用于为代码元素(类、方法、字段、参数等)添加元数据的机制。这些元数据可以在编译时、类加载时或运行时被读取并使用。注解不会直接影响代码的执行,但可以通过工具或框架来处理这些元数据,以实现一些功能。
2. 内置注解

Java 提供了一些常用的内置注解:

  • @Override:用于标注方法,表明该方法重写了父类的方法。
  • @Deprecated:用于标注过期的元素,编译器看到使用了这个元素会发出告诫。
  • @SuppressWarnings:用于抑制编译器告诫。
  1. public class AnnotationExample {
  2.     @Override
  3.     public String toString() {
  4.         return "AnnotationExample";
  5.     }
  6.     @Deprecated
  7.     public void deprecatedMethod() {
  8.         // 这个方法已经过时
  9.     }
  10.     @SuppressWarnings("unchecked")
  11.     public void suppressWarningsExample() {
  12.         List rawList = new ArrayList();
  13.         rawList.add("example");
  14.     }
  15. }
复制代码
3. 自界说注解

你可以界说自己的注解,并通过元注解(meta-annotation)来指定注解的行为。
元注解:

  • @Retention:指定注解的保留策略,取值有 RetentionPolicy.SOURCE、RetentionPolicy.CLASS、RetentionPolicy.RUNTIME。
  • @Target:指定注解可以应用的程序元素,取值有 ElementType.TYPE、ElementType.FIELD、ElementType.METHOD、ElementType.PARAMETER 等。
  • @Documented:指定注解是否包罗在 Javadoc 中。
  • @Inherited:指定注解是否可以被子类继承。
  1. import java.lang.annotation.*;
  2. @Retention(RetentionPolicy.RUNTIME) // 运行时保留
  3. @Target(ElementType.METHOD) // 作用于方法
  4. public @interface MyAnnotation {
  5.     String value();
  6. }
  7. public class MyClass {
  8.         // 当 MyClass 的 myMethod 方法被注释了这个注解后,可以通过反射在运行时获取这个注解及其值。下面的"结合注解与反射"有例子
  9.     @MyAnnotation(value = "example")
  10.     public void myMethod() {
  11.         System.out.println("Method with MyAnnotation");
  12.     }
  13. }
复制代码
Java 反射(Reflection)

1. 反射的根本概念

反射是一种运行机遇制,允许程序在运行时查抄和操纵类、方法、字段等。通过反射,你可以:

  • 获取类的详细信息(类名、修饰符、父类、接口等)。
  • 获取类的方法、构造函数、字段等。
  • 动态调用方法或构造函数。
  • 动态访问和修改字段的值。
2. 获取类的信息


  • 获取 Class 对象
有多种方法可以获取一个类的 Class 对象:
Class.forName(String className): 通过类的完全限定名获取 Class 对象。
ClassName.class: 通过类的字面常量获取 Class 对象。
object.getClass(): 通过对象实例获取 Class 对象。
  1. // 获取 Class 对象的三种方式
  2. Class<?> clazz1 = Class.forName("java.util.ArrayList");
  3. Class<?> clazz2 = ArrayList.class;
  4. ArrayList<String> list = new ArrayList<>();
  5. Class<?> clazz3 = list.getClass();
复制代码
3. 获取类的成员

getDeclaredFields(): 获取类的所有字段(包括私有字段)。
getDeclaredMethods(): 获取类的所有方法(包括私有方法)。
getDeclaredConstructors(): 获取类的所有构造函数。
getField(String name): 获取类的指定字段(不包括私有字段)。
getMethod(String name, Class... parameterTypes): 获取类的指定方法(不包括私有方法)。
getConstructor(Class... parameterTypes): 获取类的指定构造函数。
  1. Class<?> clazz = Class.forName("java.util.ArrayList");
  2. // 获取所有声明的字段
  3. Field[] fields = clazz.getDeclaredFields();
  4. for (Field field : fields) {
  5.     System.out.println("字段: " + field.getName());
  6. }
  7. // 获取所有声明的方法
  8. Method[] methods = clazz.getDeclaredMethods();
  9. for (Method method : methods) {
  10.     System.out.println("方法: " + method.getName());
  11. }
  12. // 获取所有声明的构造函数
  13. Constructor<?>[] constructors = clazz.getDeclaredConstructors();
  14. for (Constructor<?> constructor : constructors) {
  15.     System.out.println("构造函数: " + constructor.getName());
  16. }
复制代码
4. 动态创建对象

newInstance(): 使用无参构造函数创建对象。
Constructor.newInstance(Object... initargs): 使用指定构造函数创建对象。
  1. Class<?> clazz = Class.forName("java.util.ArrayList");
  2. // 使用无参构造函数创建对象
  3. Object obj1 = clazz.newInstance();
  4. // 使用带参数的构造函数创建对象
  5. Constructor<?> constructor = clazz.getConstructor(Collection.class);
  6. Collection<String> collection = Arrays.asList("A", "B", "C");
  7. Object obj2 = constructor.newInstance(collection);
  8. System.out.println(obj1);
  9. System.out.println(obj2);
复制代码
5. 动态调用方法

Method.invoke(Object obj, Object... args): 调用指定对象的该方法。
  1. Class<?> clazz = Class.forName("java.util.ArrayList");
  2. Method method = clazz.getMethod("add", Object.class);
  3. ArrayList<String> list = new ArrayList<>();
  4. method.invoke(list, "Hello");
  5. System.out.println(list); // 输出: [Hello]
复制代码
6. 动态访问和修改字段

Field.get(Object obj): 获取指定对象中此字段的值。
Field.set(Object obj, Object value): 设置指定对象中此字段的值。
  1. class MyClass {
  2.     private String field = "Initial Value";
  3. }
  4. Class<?> clazz = Class.forName("MyClass");
  5. Field field = clazz.getDeclaredField("field");
  6. field.setAccessible(true); // 如果字段是私有的,需要设置可访问
  7. MyClass obj = new MyClass();
  8. System.out.println("原始字段值: " + field.get(obj)); // 获取字段值
  9. field.set(obj, "New Value"); // 设置字段值
  10. System.out.println("修改后的字段值: " + field.get(obj)); // 获取字段值
复制代码
团结注解与反射

注解与反射的团结非常常见,尤其在框架中,例如 Spring 和 Hibernate。通过反射机制,你可以在运行时读取注解信息,并根据这些信息执行特定的操纵。
示例:简朴的依赖注入

以下示例展示了如何通过注解和反射实现简朴的依赖注入:
  1. import java.lang.annotation.*;
  2. import java.lang.reflect.*;
  3. // 定义注解
  4. @Retention(RetentionPolicy.RUNTIME)
  5. @Target(ElementType.FIELD)
  6. @interface Inject {
  7. }
  8. // 服务类
  9. class Service {
  10.     public void serve() {
  11.         System.out.println("Service is serving");
  12.     }
  13. }
  14. // 客户端类
  15. class Client {
  16.     @Inject
  17.     private Service service;
  18.     public void doSomething() {
  19.         service.serve();
  20.     }
  21. }
  22. // 注入依赖的工具类
  23. public class DependencyInjector {
  24.     public static void main(String[] args) throws Exception {
  25.         Client client = new Client();
  26.         injectDependencies(client);
  27.         client.doSomething();
  28.     }
  29.     public static void injectDependencies(Object obj) throws Exception {
  30.         Class<?> clazz = obj.getClass();
  31.         for (Field field : clazz.getDeclaredFields()) {        // 遍历client的所有字段(变量).
  32.             if (field.isAnnotationPresent(Inject.class)) {        // 获取带有Inject注解的变量, 把它注入到 Client 中
  33.                 field.setAccessible(true);
  34.                 Object dependency = field.getType().getConstructor().newInstance();
  35.                 field.set(obj, dependency);        // 通过field的set方法将service实例注入到client中
  36.             }
  37.         }
  38.     }
  39. }
复制代码
在这个示例中:

  • @Inject 注解用于标注需要注入的字段。
  • DependencyInjector 类通过反射获取 Client 类中带有 @Inject 注解的字段,并动态实例化 Service 类的对象,注入到 Client 类的实例中。
  • Client 类调用 doSomething 方法时,Service 类的实例已经被注入并可以使用。
总结

注解和反射是 Java 中非常强大和机动的机制,通过它们可以实现很多高级功能,例如依赖注入、AOP、动态代理等。在实际开发中,明白和熟练运用这些技术,可以资助你编写出更加机动、可扩展的代码。
文章到这里就这束了!~
其他文章地址:
快速入门,springboot知识点汇总
springboot常用注解大全(超详细, 30个)
springboot websocket知识点汇总
spring cloud知识点汇总, 待更

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

美食家大橙子

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表