首页 > 编程语言 >java注解与反射(非常详细, 带有很多样例)

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

时间:2024-08-02 12:58:01浏览次数:13  
标签:反射 java 获取 public clazz field 注解 Class

下面是详细地讲解 Java 中的注解与反射,并提供了很多的示例来帮助理解。

Java 注解(Annotations)

1. 注解的基本概念

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

2. 内置注解

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

  • @Override:用于标注方法,表明该方法重写了父类的方法。
  • @Deprecated:用于标注过时的元素,编译器看到使用了这个元素会发出警告。
  • @SuppressWarnings:用于抑制编译器警告。
public class AnnotationExample {
    @Override
    public String toString() {
        return "AnnotationExample";
    }

    @Deprecated
    public void deprecatedMethod() {
        // 这个方法已经过时
    }

    @SuppressWarnings("unchecked")
    public void suppressWarningsExample() {
        List rawList = new ArrayList();
        rawList.add("example");
    }
}
3. 自定义注解

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

元注解:

  • @Retention:指定注解的保留策略,取值有 RetentionPolicy.SOURCERetentionPolicy.CLASSRetentionPolicy.RUNTIME
  • @Target:指定注解可以应用的程序元素,取值有 ElementType.TYPEElementType.FIELDElementType.METHODElementType.PARAMETER 等。
  • @Documented:指定注解是否包含在 Javadoc 中。
  • @Inherited:指定注解是否可以被子类继承。
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME) // 运行时保留
@Target(ElementType.METHOD) // 作用于方法
public @interface MyAnnotation {
    String value();
}

public class MyClass {
	// 当 MyClass 的 myMethod 方法被注释了这个注解后,可以通过反射在运行时获取这个注解及其值。下面的"结合注解与反射"有例子
    @MyAnnotation(value = "example")
    public void myMethod() {
        System.out.println("Method with MyAnnotation");
    }
}

Java 反射(Reflection)

1. 反射的基本概念

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

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

有多种方法可以获取一个类的 Class 对象:

Class.forName(String className): 通过类的完全限定名获取 Class 对象。

ClassName.class: 通过类的字面常量获取 Class 对象。

object.getClass(): 通过对象实例获取 Class 对象。

// 获取 Class 对象的三种方式
Class<?> clazz1 = Class.forName("java.util.ArrayList");
Class<?> clazz2 = ArrayList.class;
ArrayList<String> list = new ArrayList<>();
Class<?> clazz3 = list.getClass();
3. 获取类的成员

getDeclaredFields(): 获取类的所有字段(包括私有字段)。

getDeclaredMethods(): 获取类的所有方法(包括私有方法)。

getDeclaredConstructors(): 获取类的所有构造函数。

getField(String name): 获取类的指定字段(不包括私有字段)。

getMethod(String name, Class<?>... parameterTypes): 获取类的指定方法(不包括私有方法)。

getConstructor(Class<?>... parameterTypes): 获取类的指定构造函数。

Class<?> clazz = Class.forName("java.util.ArrayList");

// 获取所有声明的字段
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
    System.out.println("字段: " + field.getName());
}

// 获取所有声明的方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
    System.out.println("方法: " + method.getName());
}

// 获取所有声明的构造函数
Constructor<?>[] constructors = clazz.getDeclaredConstructors();
for (Constructor<?> constructor : constructors) {
    System.out.println("构造函数: " + constructor.getName());
}
4. 动态创建对象

newInstance(): 使用无参构造函数创建对象。

Constructor.newInstance(Object... initargs): 使用指定构造函数创建对象。

Class<?> clazz = Class.forName("java.util.ArrayList");

// 使用无参构造函数创建对象
Object obj1 = clazz.newInstance();

// 使用带参数的构造函数创建对象
Constructor<?> constructor = clazz.getConstructor(Collection.class);
Collection<String> collection = Arrays.asList("A", "B", "C");
Object obj2 = constructor.newInstance(collection);

System.out.println(obj1);
System.out.println(obj2);
5. 动态调用方法

Method.invoke(Object obj, Object... args): 调用指定对象的该方法。

Class<?> clazz = Class.forName("java.util.ArrayList");
Method method = clazz.getMethod("add", Object.class);

ArrayList<String> list = new ArrayList<>();
method.invoke(list, "Hello");
System.out.println(list); // 输出: [Hello]
6. 动态访问和修改字段

Field.get(Object obj): 获取指定对象中此字段的值。

Field.set(Object obj, Object value): 设置指定对象中此字段的值。


class MyClass {
    private String field = "Initial Value";
}

Class<?> clazz = Class.forName("MyClass");
Field field = clazz.getDeclaredField("field");
field.setAccessible(true); // 如果字段是私有的,需要设置可访问

MyClass obj = new MyClass();
System.out.println("原始字段值: " + field.get(obj)); // 获取字段值

field.set(obj, "New Value"); // 设置字段值
System.out.println("修改后的字段值: " + field.get(obj)); // 获取字段值

结合注解与反射

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

示例:简单的依赖注入

以下示例展示了如何通过注解和反射实现简单的依赖注入:

import java.lang.annotation.*;
import java.lang.reflect.*;

// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Inject {
}

// 服务类
class Service {
    public void serve() {
        System.out.println("Service is serving");
    }
}

// 客户端类
class Client {
    @Inject
    private Service service;

    public void doSomething() {
        service.serve();
    }
}

// 注入依赖的工具类
public class DependencyInjector {
    public static void main(String[] args) throws Exception {
        Client client = new Client();
        injectDependencies(client);
        client.doSomething();
    }

    public static void injectDependencies(Object obj) throws Exception {
        Class<?> clazz = obj.getClass();
        for (Field field : clazz.getDeclaredFields()) {	// 遍历client的所有字段(变量).
            if (field.isAnnotationPresent(Inject.class)) {	// 获取带有Inject注解的变量, 把它注入到 Client 中
                field.setAccessible(true);
                Object dependency = field.getType().getConstructor().newInstance();
                field.set(obj, dependency);	// 通过field的set方法将service实例注入到client中
            }
        }
    }
}

在这个示例中:

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

总结

注解和反射是 Java 中非常强大和灵活的机制,通过它们可以实现许多高级功能,例如依赖注入、AOP、动态代理等。在实际开发中,理解和熟练运用这些技术,可以帮助你编写出更加灵活、可扩展的代码。

文章到这里就这束了!~

其他文章地址:

快速入门,springboot知识点汇总

springboot常用注解大全(超详细, 30个)

springboot websocket知识点汇总

spring cloud知识点汇总, 待更

标签:反射,java,获取,public,clazz,field,注解,Class
From: https://blog.csdn.net/m0_74065705/article/details/140752836

相关文章

  • [0367]基于JAVA的儿童成长档案智慧管理系统的设计与实现
    毕业设计(论文)开题报告表姓名学院专业班级题目基于JAVA的儿童成长档案智慧管理系统的设计与实现指导老师(一)选题的背景和意义背景:随着信息技术的快速发展和应用普及,社会对教育信息化、个性化以及全面性发展提出了更高的要求。尤其在儿童早期教育与健......
  • 【Java毕设选题推荐】基于SpringBoot的冀中工程技师校园网站
    前言:我是IT源码社,从事计算机开发行业数年,专注Java领域,专业提供程序设计开发、源码分享、技术指导讲解、定制和毕业设计服务......
  • 【Java毕设选题推荐】基于SpringBoot的线上招聘问答系统
    前言:我是IT源码社,从事计算机开发行业数年,专注Java领域,专业提供程序设计开发、源码分享、技术指导讲解、定制和毕业设计服务......
  • Java:进程和线程
    文章目录进程线程的概念和区别总结如何创建线程1.继承Thread重写run2.实现Runnable重写run3.继承Thread重写run,通过匿名内部类来实现虚拟线程并发编程:通过写特殊的代码,把多个CPU核心都利用起来,这样的代码就称为“并发编程”。多进程编程,就是一种典型的并发编程......
  • [0362]基于JAVA的储能EMS能量智慧管理系统的设计与实现
    毕业设计(论文)开题报告表姓名学院专业班级题目基于JAVA的储能EMS能量智慧管理系统的设计与实现指导老师(一)选题的背景和意义在当前全球能源结构转型和可持续发展战略的大背景下,储能技术作为电力系统灵活性的重要支撑手段,其智慧化、精细化管理已成为提......
  • [0359]基于JAVA的健身房人脸识别智慧管理系统的设计与实现
    毕业设计(论文)开题报告表姓名学院专业班级题目基于JAVA的健身房人脸识别智慧管理系统的设计与实现指导老师(一)选题的背景和意义选题背景与意义:随着我国全民健身意识的提高和生活质量的改善,健身房作为公众参与体育锻炼的重要场所,其运营管理和服务水平......
  • 【原创】java+ssm+mysql图书信息管理系统设计与实现
    个人主页:程序员杨工个人简介:从事软件开发多年,前后端均有涉猎,具有丰富的开发经验博客内容:全栈开发,分享Java、Python、Php、小程序、前后端、数据库经验和实战开发背景:随着数字化和信息化技术的飞速发展,传统的图书馆管理方式已经逐渐不能满足现代社会的需求。数字化技术为......
  • day16 Java基础——JavaDoc生成文档
    day16Java基础——JavaDoc生成文档目录day16Java基础——JavaDoc生成文档1.什么是JavaDoc2.生成JavaDoc2.1通过命令行生成JavaDoc2.2使用IDEA生成JavaDoc1.什么是JavaDocJavaDoc是一种标准的、用于生成Java代码API文档的工具。它通过在Java源代码中特定的......
  • java 后端 控制跨域问题
     @ComponentpublicclassUserLoginInterceptorimplementsHandlerInterceptor{ privatestaticfinalLoggerlogger=LoggerFactory.getLogger(UserLoginInterceptor.class); @Value("${zyplayer.doc.manage.originDomainRegex:}") privateStringorig......
  • 深入理解Java中的时间处理与时区管理
    在Java开发中,时间处理和时区管理是常见的需求,特别是在全球化应用中。Java8引入了新的时间API(java.time包),使时间处理变得更加直观和高效。本文将详细介绍Java中的时间处理与时区管理,通过丰富的代码示例帮助读者掌握这些概念。1.Java8之前的时间处理在Java8之前,时间处理主......