08 反射与注解

目录

1.Java类加载机制

类加载器

双亲委派模型

工作流程

优点

2.反射

基本概念

常见用法

1. 获取 Class 对象

2.获取构造方法

3.获取成员方法

4.获取成员变量

3.注解

注解的基本概念

定义和使用注解

定义注解

使用注解

解释

元注解详解

常见内置注解

总结


1.Java类加载机制

ava 类加载机制是 Java 运行时环境的核心组成部分之一,它负责将字节码文件加载到内存中,并对其进行解析和初始化。Java 类加载器采用了一种称为“双亲委派模型”的机制,这种机制确保了类的加载过程是安全和高效的。

Java 类加载器主要负责以下几个任务:

  1. 加载:将字节码文件从文件系统或网络中读取到内存中。

  2. 验证:确保加载的字节码文件符合 JVM 规范,没有安全问题。

  3. 准备:为类的静态变量分配内存,并设置默认初始值。

  4. 解析:将符号引用替换为直接引用。

  5. 初始化:执行类的初始化代码,即静态初始化块和静态变量的赋值操作。

类加载器

Java 类加载器主要有以下几种:

  1. Bootstrap ClassLoader(引导类加载器)

    • 负责加载核心的 Java 类库,如 java.lang.*java.util.* 等。

    • 通常由 C++ 编写,是 JVM 的一部分。

    • 不可以通过 Java 代码直接访问。

  2. Extension ClassLoader(扩展类加载器)

    • 负责加载 Java 的扩展库,如 javax.* 包下的类。

    • 通常加载位于 JRE/lib/ext 目录下的 JAR 文件。

  3. Application ClassLoader(应用类加载器)

    • 负责加载应用程序的类路径(classpath)上的类。

    • 通常加载用户自定义的类。

  4. 自定义类加载器

    • 用户可以根据需要编写自定义的类加载器,继承 java.lang.ClassLoader 类。

双亲委派模型

双亲委派模型是 Java 类加载器的一种层次关系,其主要目的是为了保证类的唯一性和安全性。在双亲委派模型中,当一个类加载器收到类加载请求时,它会先委托其父类加载器去加载该类,只有当父类加载器无法加载时,才会尝试自己加载。

工作流程
  1. 检查是否已经加载

    • 类加载器首先检查该类是否已经被加载过,如果已经加载,则直接返回已加载的类。

  2. 委托给父类加载器

    • 如果类未被加载,则委托给父类加载器去加载。

  3. 父类加载器递归委托

    • 父类加载器重复上述步骤,直到到达最顶层的 Bootstrap ClassLoader。

  4. 加载类

    • 如果所有父类加载器都无法加载该类,则由当前类加载器尝试加载。

优点
  1. 避免类的重复加载

    • 通过双亲委派模型,确保了类的唯一性,避免了不同类加载器加载同一个类导致的问题。

  2. 安全性

    • 核心类库由 Bootstrap ClassLoader 加载,确保了核心类库的安全性,防止被恶意代码篡改。

2.反射

Java 反射(Reflection)是一种强大的机制,允许程序在运行时动态地获取类的信息并操作对象。通过反射,你可以获取类的构造器、方法、字段等信息,甚至可以在运行时调用私有方法和修改私有字段。以下是关于 Java 反射的一些基本概念和常见用法。

基本概念
  1. Class 类

    • Class 是 Java 反射的核心类,代表类的类型信息。

    • 可以通过 Class.forName、对象的 .getClass 方法或直接使用类的 .class 字段来获取 Class 对象。

  2. Constructor 类

    • 表示类的构造器。

    • 可以通过 Class 对象的 getConstructorsgetDeclaredConstructorsgetConstructorgetDeclaredConstructor 方法获取。

  3. Method 类

    • 表示类的方法。

    • 可以通过 Class 对象的 getMethodsgetDeclaredMethodsgetMethodgetDeclaredMethod 方法获取。

  4. Field 类

    • 表示类的字段。

    • 可以通过 Class 对象的 getFieldsgetDeclaredFieldsgetFieldgetDeclaredField 方法获取。

常见用法
1. 获取 Class 对象
  • 通过类名获取对象

  • 通过对象getClass()方法获取

  • 通过.class属性获取

    // 通过类名获取
    Class<?> clazz1 = Class.forName("com.example.MyClass");
    ​
    // 通过对象获取
    MyClass obj = new MyClass();
    Class<?> clazz2 = obj.getClass();
    ​
    // 通过类的 .class 属性获取
    Class<?> clazz3 = MyClass.class;
2.获取构造方法
  • 获取所有构造方法

  • 获取指定参数类型构造方法

    // 获取所有public的构造器
    Constructor<?>[] constructors = MyClass.class.getConstructors();
    ​
    // 获取指定类型参数构造器
    Constructor<MyClass> constructor = MyClass.class.getConstructor(int.class, String.class);
3.获取成员方法
  • 获取public方法

  • 获取所有方法,包含private的

    // 获取指定方法
    Method method = MyClass.class.getMethod("myMethod", String.class);
    ​
    // 调用方法
    String result = (String) method.invoke(obj, "parameter");
    ​
    // 获取所有public方法
    Method[] methods = MyClass.class.getMethods();
    ​
    // 获取所有方法,包含private
    Method[] privateMethods = MyClass.class.getDeclaredMethods();
4.获取成员变量
  • 获取public变量

  • 获取所有变量,包括private的

    // 获取所有public的成员变量
    Field[] fields = MyClass.class.getFields();
    ​
    // 获取所有属性,包括private的成员变量
    Field[] privateFields = MyClass.class.getDeclaredFields();
    ​
    // 获取指定字段
    Field field = MyClass.class.getDeclaredField("myField");
    ​
    // 设置字段可访问(即使它是私有的)
    field.setAccessible(true);
    ​
    // 设置字段值
    field.set(obj, "new value");
    ​
    // 获取字段值
    String value = (String) field.get(obj);

定义一个Person类

public class Person {private String name;private Integer age;
​public Person() {}
​//私有构造private Person(String name){this.name = name;}
​public Person(String name, Integer age) {this.name = name;this.age = age;}
​public String getName() {return name;}
​public void setName(String name) {this.name = name;}
​public Integer getAge() {return age;}
​public void setAge(Integer age) {this.age = age;}
​@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}

简单练习:

public class ReflectTest {public static void main(String[] args) {try {System.out.println("=========反射获取对象:通过全限定类名=========");// 反射:通过类名获取类对象,类名必须是全限定类名:包名+类名Class<?> clazz = Class.forName("com.haha.test.Person");System.out.println(clazz);
​System.out.println("=========反射获取对象:通过对象getClass()方法=========");// 反射:通过类名获取类对象Person person = new Person("xiaoming", 18, "male");Class<?> clazz2 = person.getClass();System.out.println(clazz2);
​System.out.println("=========反射获取对象:通过.class属性=========");// 反射:通过类名获取类对象Class<?> clazz3 = Person.class;System.out.println(clazz3);
​System.out.println("=========反射获取所有public的构造方法=========");Constructor<?>[] constructors = clazz.getConstructors();for (Constructor<?> constructor : constructors) {System.out.println(constructor);}
​System.out.println("=========反射获取指定参数类型的构造方法=========");Constructor<?> constructor = clazz.getConstructor(String.class, int.class, String.class);System.out.println(constructor);
​System.out.println("=========反射获取所有public的成员方法=========");Method[] methods = clazz.getMethods();for (Method method : methods) {System.out.println(method);}
​System.out.println("=========反射获取私有的成员方法=========");Method[] privateMethods = clazz.getDeclaredMethods();for (Method method : privateMethods) {System.out.println(method);}
​System.out.println("=========反射获取所有public的成员变量=========");Field[] fields = clazz.getFields();for (Field field : fields) {System.out.println(field);}
​System.out.println("=========反射获取所有属性,包括private的成员变量=========");Field[] privateFields = clazz.getDeclaredFields();for (Field field : privateFields) {System.out.println(field);// 设置字段可访问(即使它是私有的)field.setAccessible(true);
​// 获取字段名称和类型String fieldName = field.getName();Class<?> fieldType = field.getType();
​// 根据字段类型设置新值if (fieldType.equals(String.class)) {field.set(person, "New " + fieldName);} else {field.set(person, 35);}
​// 打印字段值System.out.println(field.get(person));}} catch (Exception e) {System.out.println(e.getMessage());}}
}

3.注解

注解(Annotations)是 Java 语言的一个重要特性,用于提供元数据信息,这些信息可以被编译器、运行时环境或其他工具使用。注解本身并不会直接影响程序的行为,但可以通过反射机制在运行时读取这些注解,并根据注解的信息执行相应的逻辑。

注解的基本概念
  1. 元注解

    • 元注解是用于注解其他注解的注解。常见的元注解包括:

      • @Retention:指定注解的保留策略。

      • @Target:指定注解可以应用的目标。

      • @Documented:指定注解是否会被包含在 JavaDoc 中。

      • @Inherited:指定注解是否可以被子类继承。

  2. 内置注解

    • @Override:表示方法重写父类或实现接口中的方法。

    • @Deprecated:表示方法或类已过时。

    • @SuppressWarnings:抑制编译器警告。

  3. 自定义注解

    • 开发者可以自定义注解,以满足特定的需求。

定义和使用注解
定义注解

定义一个注解需要使用 @interface 关键字。以下是一个简单的自定义注解示例:

java深色版本

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.METHOD, ElementType.FIELD })
public @interface MyAnnotation {// 注解的属性String value() default "";int id() default -1;
}
使用注解

在类、方法或字段上使用自定义注解:

java深色版本

public class MyClass {
​@MyAnnotation(value = "Hello", id = 1)private String myField;
​@MyAnnotation(value = "World", id = 2)public void myMethod() {System.out.println("This is my method.");}
​public static void main(String[] args) {MyClass obj = new MyClass();obj.myMethod();
​// 通过反射读取注解信息readAnnotations(obj);}
​private static void readAnnotations(Object obj) {// 获取类的 Class 对象Class<?> clazz = obj.getClass();
​// 获取类的所有字段Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {// 检查字段是否有 MyAnnotation 注解if (field.isAnnotationPresent(MyAnnotation.class)) {MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);System.out.println("Field: " + field.getName());System.out.println("Value: " + annotation.value());System.out.println("ID: " + annotation.id());}}
​// 获取类的所有方法Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {// 检查方法是否有 MyAnnotation 注解if (method.isAnnotationPresent(MyAnnotation.class)) {MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);System.out.println("Method: " + method.getName());System.out.println("Value: " + annotation.value());System.out.println("ID: " + annotation.id());}}}
}
解释
  1. 定义注解

    • 使用 @interface 关键字定义注解 MyAnnotation

    • 使用 @Retention(RetentionPolicy.RUNTIME) 指定注解的保留策略为运行时,这意味着注解信息会在运行时可用。

    • 使用 @Target({ ElementType.METHOD, ElementType.FIELD }) 指定注解可以应用于方法和字段。

    • 注解包含两个属性 valueid,并分别设置了默认值。

  2. 使用注解

    • MyClass 类中,使用 @MyAnnotation 注解标注字段 myField 和方法 myMethod

    • main 方法中,创建 MyClass 的实例并调用 myMethod

  3. 通过反射读取注解信息

    • 使用 Class 对象获取类的所有字段和方法。

    • 使用 isAnnotationPresent 方法检查字段或方法是否有 MyAnnotation 注解。

    • 使用 getAnnotation 方法获取注解实例,并读取注解的属性值。

元注解详解
  1. @Retention

    • RetentionPolicy.SOURCE:注解仅保留在源代码中,编译时会被忽略。

    • RetentionPolicy.CLASS:注解保留在字节码文件中,但运行时不可用。

    • RetentionPolicy.RUNTIME:注解保留在字节码文件中,运行时可通过反射读取。

  2. @Target

    • ElementType.TYPE:类、接口、枚举。

    • ElementType.FIELD:字段。

    • ElementType.METHOD:方法。

    • ElementType.PARAMETER:方法参数。

    • ElementType.CONSTRUCTOR:构造器。

    • ElementType.LOCAL_VARIABLE:局部变量。

    • ElementType.ANNOTATION_TYPE:注解类型。

    • ElementType.PACKAGE:包。

  3. @Documented

    • 指定注解是否会被包含在 JavaDoc 中。

  4. @Inherited

    • 指定注解是否可以被子类继承。

常见内置注解
  1. @Override

    • 表示方法重写父类或实现接口中的方法。

  2. @Deprecated

    • 表示方法或类已过时,不推荐使用。

  3. @SuppressWarnings

    • 抑制编译器警告。

总结

注解是 Java 中一个非常强大的特性,可以用于提供元数据信息,帮助编译器、运行时环境或其他工具更好地理解和处理代码。通过自定义注解和反射机制,可以实现灵活的代码管理和功能扩展。希望这些示例和解释对你有所帮助!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/59829.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux第八课-进程间通信】管道、共享内存、消息队列、信号量、信号、可重入函数、volatile

目录 进程间通信为什么&#xff1f;是什么&#xff1f;怎么办&#xff1f;一般规律具体做法 匿名管道原理代码 命名管道原理代码 system V共享内存消息队列信号量信号量的接口 信号概念为什么&#xff1f;怎么办&#xff1f;准备信号的产生信号的保存概念三张表匹配的操作和系统…

【一些正经的思考】牵牛花在秋天播种可以开花吗

这是一篇正经的思考&#xff0c;因为是发生在工位上的事情&#xff0c;所以这也是上班记录~ 我入职新公司已经两个月了&#xff0c;和部门的新伙伴出去吃饭的频率高了1000%&#xff0c;不得不说&#xff0c;这边的食堂确实不是那么好吃&#xff0c;就和小伙伴经常去一个在江边…

零基础Java第十四期:继承与多态(二)

目录 一、继承 1.1. 继承的方式 1.2. final关键字 1.3. 继承与组合 1.4. protected关键字 二、多态 2.1. 多态的概念 2.2. 向上转型 2.3. 重写 2.4. 向下转型 2.5. 多态的优缺点 一、继承 1.1. 继承的方式 猫类可以继承动物类&#xff0c;中华田园猫类可以继承猫类…

RocketMQ 广播消息

所谓的广播消息就是发送的一条消息会被多个消费者收到。 ⼴播是向主题&#xff08; topic &#xff09;的所有订阅者发送消息。订阅同⼀个 topic 的多个消费者&#xff0c;能全量收到⽣产者发送的所有消息。 生产者发送了10个order&#xff0c;每个order里面有5个消息&#xff…

.Net IOC理解及代码实现

IOC理解 IoC(Inversion of Control)&#xff1a;即控制反转&#xff0c;这是一种设计思想&#xff0c;指将对象的控制权交给IOC容器&#xff0c;由容器来实现对象的创建、管理&#xff0c;程序员只需要从容器获取想要的对象就可以了。DI(Dependency Injection)&#xff0c;即依…

react的创建与书写

一&#xff1a;创建项目 超全面详细一条龙教程&#xff01;从零搭建React项目全家桶&#xff08;上篇&#xff09; - 知乎 1.创建一个文件夹&#xff0c;shift鼠标右键选择在此处打开powershell 2.为了加速npm下载速度&#xff0c;先把npm设置为淘宝镜像地址。 npm config s…

【微信小游戏学习心得】

这里是引用 微信小游戏学习心得 简介了解微信小游戏理解2d游戏原理数据驱动视图总结 简介 本人通过学习了解微信小游戏&#xff0c;学习微信小游戏&#xff0c;加深了对前端框架&#xff0c;vue和react基于数据驱动视图的理解&#xff0c;及浏览器文档模型和javaScript之间的关…

深究JS底层原理

一、JS中八种数据类型判断方法 在JavaScript中&#xff0c;数据类型分为两大类&#xff1a;基本&#xff08;原始&#xff09;数据类型和引用&#xff08;对象&#xff09;数据类型。 基本数据类型&#xff08;Primitive Data Types&#xff09; 基本数据类型是表示简单的数…

ssm071北京集联软件科技有限公司信息管理系统+jsp(论文+源码)_kaic

毕 业 设 计&#xff08;论 文&#xff09; 题目&#xff1a;北京集联软件科技有限公司信息管理系统 \ 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本信息…

Yocto 项目下通过网络更新内核、设备树及模块

Yocto 项目下通过网络更新内核、设备树及模块 前言 在 Yocto 项目的开发过程中&#xff0c;特别是在进行 BSP&#xff08;Board Support Package&#xff09;开发时&#xff0c;经常需要调整特定软件包的版本&#xff0c;修改内核、设备树以及内核模块。然而&#xff0c;每次…

k8s集群安装(kubeadm)

k8s集群安装&#xff08;kubeadm&#xff09; 1、环境准备&#xff08;master和node节点都执行&#xff09;1.1、替换yum源1.2、关闭selinux1.3、永久关闭防火墙1.4、永久关闭swap1.5、修改主机名添加host1.6、时间同步1.7、将桥接的IPv4流量传递到iptables的链1.8、docker安装…

【日常问题排查小技巧-连载】

线上服务CPU飙高排查 先执行 top&#xff0c;找到CPU占用比较高的进程 id&#xff0c;&#xff08;比如 21448&#xff09; jstack 进程 id > show.txt&#xff08;jstack 21448 > show.txt&#xff09; 找到进程中CPU占用比较高的线程&#xff0c;线程 id 转换为 16 进…

您与此网站之间建立的连接不安全解决方法

如果你打开网站&#xff0c;地址栏有警告&#xff0c;点进去是这样的提示&#xff1a;您与此网站之间建立的连接不安全&#xff0c;了解详细信息。 请勿在此网站上输入任何敏感信息&#xff08;例如密码或信用卡信息&#xff09;&#xff0c;因为攻击者可能会盗取这些信息。 …

【与AI+】学习SAP开发有什么渠道可以推荐

前言&#xff1a;好的&#xff0c;我又将开辟一个新的专栏&#xff0c;这个专栏呢&#xff0c;就准备放一些我向AI提问的问题&#xff0c;以及AI的回答。因为感觉真的好方便哈哈哈~ 我不是很确定我的专栏文章内容是否涉及版权&#xff0c;以及也不确定这些整合过的文字是否涉嫌…

江苏博才众创科技产业园集团拟投资10亿元在泰兴打造汽车零部件产业园

2024年11月7日&#xff0c;泰兴市高新技术产业开发区与江苏博才众创科技产业园集团举行新能源汽车零部件智能制造产业园项目签约仪式。 泰兴市高新区党工委委员、管理办副主任王峰表示&#xff1a;高新区是全市项目建设的主阵地&#xff0c;近年来聚焦高端化、智能化、绿色化&a…

【python】Flask

文章目录 1、Flask 介绍2、Flask 实现网页版美颜效果3、参考 1、Flask 介绍 Flask 是一个用 Python 编写的轻量级 Web 应用框架。它设计简单且易于扩展&#xff0c;非常适合小型项目到大型应用的开发。 以下是一些 Flask 库中常用的函数和组件&#xff1a; 一、Flask 应用对…

产品经理如何使用项目管理软件推进复杂项目按时上线

前言 相信很多产品同学或多或少都有过这样的经历&#xff1a;平时没有听到任何项目延期风险&#xff0c;但到了计划时间却迟迟无法提测……评审时没有任何argue&#xff0c;提测后发现开发的功能不是自己想要的……费劲九牛二虎之力终于让项目上线了&#xff0c;然而发现成果达…

新系统如何进行模型环境配置

在机器学习和深度学习中&#xff0c;一个良好的开发环境能够显著提高工作效率。本篇博客将详细介绍如何在新的Linux系统&#xff08;以Ubuntu为例&#xff09;上进行模型环境的配置&#xff0c;包括基础系统设置、Python虚拟环境搭建、常用库的安装以及GPU驱动和CUDA的安装等。…

OpenAI大事记;GPT到ChatGPT参数量进化

目录 OpenAI大事记 GPT到ChatGPT参数量进化 OpenAI大事记 GPT到ChatGPT参数量进化 ChatGPT是从初代 GPT逐渐演变而来的。在进化的过程中,GPT系列模型的参数数量呈指数级增长,从初代GPT的1.17亿个参数,到GPT-2的15 亿个参数,再到 GPT-3的1750 亿个参数。模型越来越大,训练…

Am I Isolated:一款安全态势基准测试工具

基于Rust的容器运行时扫描器作为一个容器运行&#xff0c;检测用户容器运行时隔离中的漏洞。 它还提供指导&#xff0c;帮助用户改善运行时环境&#xff0c;以提供更强的隔离保证。 容器的现状是它们并不包含&#xff08;隔离&#xff09;。 容器隔离的缺失在云原生环境中有…