Java 注解与反射(超详细!!!)

Java 注解与反射(超详细!!!)

文章目录

  • Java 注解与反射(超详细!!!)
    • 1.注解
      • 1.1内置注解
        • 1.1.1 @SuppressWarnings注解用法
      • 1.2 元注解
      • 1.3自定义注解
    • 2.反射
      • 2.1 反射的用途
      • 2.2 反射的使用方法
      • 2.3 class类型的对象使用场景1:
      • 2.4 class类型的对象使用场景2:
      • 2.5 通过反射创造对象
      • 2.6 使用反射机制获取和调用类的构造方法,访问私有构造方法并创建对象
      • 2.7 通过反射,访问并使用成员方法

1.注解

1.1内置注解

注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

例如:

@override:定义在java.lang.override 中,此注释只适用于修辞方法,表示一个方法声明打算
重写超类中的另一个方法声明

@Deprecated:定义在java.lang.Deprecated中,此注释可以用于修辞方法,属性,类,表示不
鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择

@SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息.与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数都是已经定义好了的,我们选择性的使用就好了

例如

@SuppressWarnings("all")@SuppressWarnings("unchecked")@SuppressWarnings(value={unchecked", "deprecation")
、、、

接下来,我们通过一个案例,讲解一下注解是如何使用的,该如何使用。

//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.public class Main implements Sum {public static void main(String[] args) {Main m = new Main();m.sum();m.sum1();}@Deprecated //  不建议使用的注解public void sum1() {System.out.println("nihao11111");}@Overridepublic void sum() {System.out.println("nihao");}}

在此案例中,我们通过了@Deprecated 表明这个一个不建议使用的方法。但是,这仅仅是建议,我们仍然可以使用。

1.1.1 @SuppressWarnings注解用法

@SuppressWarnings 批注允许您选择性地取消特定代码段(即,类或方法)中的警告。其中的想法是当您看到警告时,您将调查它,如果您确定它不是问题,

就可以添加一个 @SuppressWarnings 批注,以使您不会再看到警告。虽然它听起来似乎会屏蔽潜在的错误,但实际上它将提高代码安全性,因为它将防止您对警告无动于衷 — 您看到的每一个警告都将值得注意。

例如下面这个例子,idea会爆一个警告,上述代码编译通过且可以运行,但每行前面的“感叹号”就严重阻碍了我们判断该行是否设置的断点了。这时我们可以在方法前添加@SuppressWarnings(“unused”) 去除这些“感叹号”。

Contents of collection 'items' are updated, but never queried
package 蓝桥杯国赛刷题;import java.util.ArrayList;
import java.util.List;public class commentTest01 {public static void main(String[] args) {commentTest01 CommentTest01 = new commentTest01();CommentTest01.addItems("1234");}public void addItems(String item) {List items = new ArrayList();items.add(item);}
}

1.2 元注解

元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明.

这些类型和它们所支持的类在java.lang.annotation包中可以找到分别是@Target, @Retention ,@Documented , @lnherited

@Target:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
@Retention :表示需要在什么级别保存该注释信息,用于描述注解的生命周期
@Document:说明该注解将被包含在javadoc中
@lnherited:说明子类可以继承父类中的该注解

1.3自定义注解

我们根据先前的注解写法,模仿自己写一个注解

在这里插入图片描述

通过观察创造注解包含以下元素@interface ,@Documented,@Retention,Target使用 @interface自定义注解时,自动继承了java.lang.annotation.Annotation接口

@ intertace用来声明一个注解,格式:public @ intertace 注解名{定义内容}

其中的每一个方法实际上是声明了一个参数,方法的名称就是参数的名称返回值类型就是参数的类型( 返回值只能是基本类型,Class, String, enum )。可以通过default来声明参数的默认值。如果只有一个参数成员,一般参数名为value。注解元素必须要有值,我们定义注解元素时,经常使用空字符串,O作为默认值。

自定义注解样例:

//自定义注解
public class test03 {//注解可以显示赋值, 如果没有默认值,我们就必须给注解赋值//注解参数的顺序随意@MyAnnotation2(age = 18, name = "jacky")public void test() {}@MyAnnotation3("jacky")public void test2() {}
}@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{//注解的参数: 参数类型 + 参数名 + ();String name() default "";int age() default 0;int id() default -1;String[] schools() default {"peking university"};
}@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{//如果注解参数为value赋值时可以直接写值String value();
}

在这个例子我们,我们定义了两个注解,分别是@MyAnnotation2,@MyAnnotation3,其参数不相同。

2.反射

反射(Reflection)是一种 Java 程序运行期间动态技术,可以在运行时(runtime)检査、修改其自身结构或行为。通过反射,程序可以访问、检测和修改它自己的类、对象、方法、属性等成员

在连接数据库中,反射的作用在于使用其特殊机制,直接调用目标类的构造方法。类如这段代码中

Class.forName("com.mysql.jdbc.Driver");

通过反射的机制,将 com.mysql.jdbc.Driver 这个类加载到 JVM 中。触发静态初始化块:MySQL 的驱动类在静态初始化块中会执行 DriverManager.registerDriver(new Driver()),自动向 DriverManager 注册自己,使得后续可以通过 DriverManager.getConnection()建立数据库连接。

2.1 反射的用途

  • 动态加载类:程序可以在运行时动态地加载类库中的类;
  • 动态创建对象:反射可以基于类的信息,程序可以在运行时,动态创建对象实例;
  • 调用方法:反射可以根据方法名称,程序可以在运行时,动态地调用对象的方法(即使方法在编写程序时还没有定义)
  • 访问成员变量:反射可以根据成员变量名称,程序可以在运行时,访问和修改成员变量(反射可以访问私有成员变量)
  • 运行时类型信息:反射允许程序在运行时,查询对象的类型信息,这对于编写通用的代码和库非常有用;

​ Spring 框架使用反射来自动装配组件,实现依赖注入;

​ MyBatis 框架使用反射来创建resultType 对象,封装数据查询结果;

2.2 反射的使用方法

反射的第一步是获取 Class 对象。Class 对象表示某个类的元数据,可以通过以下几种方式获取:

//获取Class类型信息
public class Text02 {public static void main(String[] args) throws ClassNotFoundException {//方式1:通过类名Class stringClass1 = String.class;//方式2:通过Class类的forName()方法Class stringClass2 = Class.forName("java.lang.String");//方式3:通过对象调用getClass()方法Class stringClass3 = "".getClass();System.out.println(stringClass1.hashCode());//1604839423System.out.println(stringClass2.hashCode());//1604839423System.out.println(stringClass3.hashCode());//1604839423}}

2.3 class类型的对象使用场景1:

//Class类型的对象使用场景1
public class Text03 {public static void main(String[] args) {String json= "{\"name\":\"长安荔枝\",\"favCount\":234}";         Document doc=JSON.parseObject(json,Document.class);System.out.println(doc.getName());System.out.println(doc.getFavCount());}}

使用 JSON.parseObject 方法将 JSON 字符串解析为 Document 类的对象。在解析过程中,JSON 字符串中的数据会自动映射到 Document 类的对应字段中。

2.4 class类型的对象使用场景2:

通过 Class 对象在运行时获取一个类的相关信息,包括类名、包名、成员变量(字段)、成员方法等。

//Class类型的对象使用场景2
//获取丰富的类型内容
public class Text04 {public static void main(String[] args) throws ClassNotFoundException {Class clz = Class.forName("java.util.HashMap");//获取类名System.out.println("完全限定名:"+clz.getName());System.out.println("简单的类名:"+clz.getSimpleName());//获取包名System.out.println("package"+clz.getPackage().getName());System.out.println();//获取成员变量Field[] fieldArray =clz.getDeclaredFields();System.out.println("成员变量(字段)");for(Field field:fieldArray) {System.out.println(field);}System.out.println();//获取成员方法Method[] methodArray = clz.getDeclaredMethods();System.out.println("成员方法");for(Method method:methodArray) {System.out.println(method);}	}
}
  • clz.getName() 返回类的完全限定名,包括包名,例如 "java.util.HashMap"
  • clz.getSimpleName() 返回类的简单名称,不包括包名,例如 "HashMap"
  • clz.getPackage().getName() 返回类所属的包名,例如 "java.util"
  • clz.getDeclaredFields() 返回一个 Field 数组,包含了类声明的所有字段(包括私有字段)。
  • clz.getDeclaredMethods() 返回一个 Method 数组,包含了类声明的所有方法(包括私有方法)。

2.5 通过反射创造对象

有两种方式通过反射创造对象分别是:

方式一:通过 Class 对象直接调用 newInstance() 方法

方式二:通过获取构造方法(Constructor)来创建对象。

//通过反射的方式,创建对象
public class Text05 {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {Class clz = Class.forName("com.apesource.demo01.Document");//方式1:直接通过Class对象,调用newInstance()方法Object objx = clz.newInstance();//相当于在执行无参构造方法//方式2:通过构造器(构造方法)//无参构造方法Constructor constructor1 = clz.getDeclaredConstructor();//获取无参构造方法System.out.println(constructor1);Object obj1 = constructor1.newInstance();//执行构造器(构造方法),创建对象//有参构造方法Constructor constructor2 = clz.getDeclaredConstructor(String.class);//获取有参构造方法System.out.println(constructor2);Object obj2 = constructor2.newInstance("两京十五日");Constructor constructor3 = clz.getDeclaredConstructor(int.class);//获取有参构造方法System.out.println(constructor3);Object obj3 = constructor3.newInstance(34);Constructor constructor4 = clz.getDeclaredConstructor(String.class,int.class);//获取有参构造方法System.out.println(constructor4);Object obj4 = constructor4.newInstance("风起陇西",64);System.out.println(objx);System.out.println(obj1);System.out.println(obj2);System.out.println(obj3);System.out.println(obj4);}
  • newInstance() 方法是 Class 对象提供的一个方法,它调用类的无参构造方法来创建类的实例。
  • 注意:这个方法在 Java 9 以后已经被弃用,推荐使用 Constructor 对象来创建实例。
  • 通过 getDeclaredConstructor() 方法获取 Document 类的无参构造方法,然后调用 newInstance() 方法创建实例。
  • 注意:如果类中没有无参构造方法,调用 getDeclaredConstructor() 会抛出 NoSuchMethodException
  • 通过 getDeclaredConstructor(String.class) 获取带有一个 String 参数的构造方法,并传入 "两京十五日" 作为参数来创建对象。
  • 通过 getDeclaredConstructor(int.class) 获取带有一个 int 参数的构造方法,并传入 34 作为参数来创建对象。

2.6 使用反射机制获取和调用类的构造方法,访问私有构造方法并创建对象

public class Text06 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {Class clz = Class.forName("com.apesource.demo01.Document");//获取一组构造器Constructor[] constructorArray1 = clz.getConstructors();//publicConstructor[] constructorArray2 = clz.getDeclaredConstructors();//public、private//获取指定构造器Constructor constructor1 = clz.getConstructor();Constructor constructor2 = clz.getDeclaredConstructor(String.class);System.out.println(constructor1);System.out.println(constructor2);//调用私有构造器,必须设置它的访问全限constructor2.setAccessible(true);//调用构造器,创建对象Object obj = constructor2.newInstance("长安三万里");System.out.println(obj);}}
  • getConstructors() 方法返回一个包含所有公共(public)构造方法的数组。如果类中没有 public 构造方法,则返回空数组。
  • getDeclaredConstructors() 方法返回一个包含所有声明的构造方法的数组(包括私有的、受保护的和默认访问级别的构造方法)。
  • getConstructor() 方法用于获取类的无参构造方法(必须是 public 的)。如果没有无参构造方法或者不是 public,则抛出 NoSuchMethodException
  • getDeclaredConstructor(Class<?>... parameterTypes) 方法用于获取指定参数类型的构造方法。这里通过传入 String.class 参数获取一个带有 String 参数的构造方法。这个构造方法可以是任何访问级别(publicprivateprotected、默认)。
  • setAccessible(true) 用于绕过 Java 访问控制机制,使私有构造方法也可以被调用。如果不设置 Accessibletrue,那么调用私有构造方法时会抛出 IllegalAccessException
  • newInstance(Object... initargs) 方法使用指定的构造方法创建对象。这里调用了带有 String 参数的构造方法,并传入 "长安三万里" 作为参数。

2.7 通过反射,访问并使用成员方法

public class Text08 {public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {//硬编码的方式
//		Document doc1 = new Document();
//		doc1.setName("海底两万里");
//		doc1.setFavCount(10025);//反射的方式Class clz = Class.forName("com.apesource.demo01.Document");//获取类型信息Object doc1 = clz.newInstance();//创建对象//获取指定名称和参数类型的方法Method setNameMethod = clz.getMethod("setName", String.class);Method setFavCountMethod = clz.getMethod("setFavCount", int.class);//执行方法//doc1.setName("海底两万里");setNameMethod.invoke(doc1, "海底两万里");//doc1.setFavCount(10025);setFavCountMethod.invoke(doc1, 10025);System.out.println(doc1);}}
  • getMethod(String name, Class<?>... parameterTypes) 方法用于获取类的某个 public 方法。方法名称和参数类型必须匹配才能成功获取方法。
  • invoke(Object obj, Object... args) 方法用于调用指定的实例方法。
  • setNameMethod.invoke(doc1, "海底两万里"); 等同于 doc1.setName("海底两万里");
  • setFavCountMethod.invoke(doc1, 10025); 等同于 doc1.setFavCount(10025);

以上便是Java注解与反射的全部内容了,笔者编写不易,恳请点赞收藏,欢迎评论区交流!!!

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

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

相关文章

用nz-tabel写一个合并表格

用nz-tabel写一个合并表格 <nz-table #basicTable [nzData]"tableSearchStatus.dataList" nzBordered><thead><tr><th>班级</th><th>姓名</th><th>年龄</th><th>电话</th></tr></thead&…

第6章 放大电路的反馈

本章基本要求 会判&#xff1a;判断电路中有无反馈及反馈的性质 会算&#xff1a;估算深度负反馈条件下的放大倍数 会引&#xff1a;根据需求引入合适的反馈 会判振消振&#xff1a;判断电路是否能稳定工作&#xff0c;会消除自激振荡。 6.1 反馈的概念及判断 一、反馈的…

ansible template 文件中如果包含{{}} 等非ansible 变量处理

在 Ansible 模板中&#xff0c;如果你的 Python 脚本里有大量 {}、f""、或者其他 Jinja 会误解析的语法&#xff0c;就需要用 {% raw %}…{% endraw %} 把它们包起来&#xff0c;只在需要替换变量的那一行单独“放行”。例如&#xff1a; {% raw %} #!/usr/bin/env …

STM32G4 电机外设篇(一) GPIO+UART

目录 一、STM32G4 电机外设篇&#xff08;一&#xff09; GPIOUART1 GPIO1.1 STM32CUBEMX 配置以及Keil代码1.2 代码和实验现象 2 UART2.1 STM32CUBEMX 配置以及Keil代码2.2 代码和实验现象 附学习参考网址欢迎大家有问题评论交流 (* ^ ω ^) 一、STM32G4 电机外设篇&#xff0…

Kotlin 中集合遍历有哪几种方式?

1 for-in 循环&#xff08;最常用&#xff09; val list listOf("A", "B", "C") for (item in list) {print("$item ") }// A B C 2 forEach 高阶函数 val list listOf("A", "B", "C") list.forEac…

尚硅谷redis7 99 springboot整合redis之连接集群

6381宕机&#xff0c;手动shutdown后在redis中&#xff0c;634自动上位变成master结点。 但是在springboot中却没有动态感知道redisCluster的最新集群消息&#xff0c;所以找不到我们要检索的数据。原因是&#xff1a;SpringBoot 2.X版本,Redis默认的连接池采用 Lettuce&#…

AI 的早期萌芽?用 Swift 演绎约翰·康威的「生命游戏」

文章目录 摘要描述题解答案题解代码分析示例测试及结果时间复杂度空间复杂度总结 摘要 你有没有想过&#xff0c;能不能通过简单的规则模拟出生与死亡&#xff1f;「生命游戏」正是这样一种充满魅力的数学模拟系统。这篇文章我们来聊聊它的规则到底有多神奇&#xff0c;并用 S…

web ui自动化工具playwright

playwright是微软开源的一款web ui自动化工具&#xff0c;该工具有很多亮点&#xff0c;解决以前困扰web UI自动化测试的很多难点。这篇博客将介绍playwright主要特点。 playwright支持录制减少了编写成本 如果要使用playwright的录制功能&#xff0c;有两种途径&#xff0c;途…

移动安全Android——客户端静态安全

一、反编译保护 测试工具 Jadx GitHub - skylot/jadx: Dex to Java decompiler PKID [下载]PKID-APP查壳工具-Android安全-看雪-安全社区|安全招聘|kanxue.com 测试流程 &#xff08;1&#xff09;通过Jadx对客户端APK文件进行反编译&#xff0c;观察是否进行代码混淆 &…

04-redis-分布式锁-edisson

1 基本概念 百度百科&#xff1a;控制分布式系统之间同步访问共享资源方式。 在分布式系统中&#xff0c;常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源&#xff0c;那么访问这些资源的时候&#xff0c;往往需要互斥来防止…

cf每日刷题

目录 String&#xff08;800&#xff09; Skibidus and Amogu&#xff08;800&#xff09; Apples in Boxes&#xff08;1100&#xff09; String&#xff08;800&#xff09; https://codeforces.com/problemset/problem/2062/A #include <iostream> #include <…

AWS WebRTC:获取ICE服务地址(part 1)

建立WebRTC连接的第二步是获取ICE服务地址。 ICE全称&#xff1a;Interactive Connectivity Establishment&#xff0c;建立互动连接。 ICE 服务地址&#xff0c;主要是 TURN 和 STUN 服务器的地址&#xff0c;用于 WebRTC 在 NAT 网络环境中协商建立连接。 上代码&#xff…

Python兴趣匹配算法:从理论到实战的进阶指南

目录 一、兴趣匹配算法的技术栈解析 1. 基础特征匹配阶段 2. 向量空间模型阶段 3. 深度学习阶段 二、工程化实践关键技术 1. 特征工程体系 2. 相似度计算优化 三、典型应用场景实现 1. 社交好友推荐系统 2. 电商商品推荐系统 四、性能优化与挑战应对 1. 计算性能优…

【C语言】讲解 程序分配的区域(新手)

目录 代码区 数据区 堆区 栈区 常量区 重点比较一下堆区与 栈区 总结&#xff1a; 前言&#xff1a; C语言程序的内存分配区域是理解其运行机制的重要部分。根据提供的多条证据&#xff0c;我们可以总结出C语言程序在运行时主要涉及以下五个关键内存区域&#xff1a; 代…

Go语言之接口与多态 -《Go语言实战指南》

接口是 Go 语言实现 多态 的核心机制。本章将帮助你理解接口的设计哲学、动态行为&#xff0c;以及它如何让 Go 实现面向接口编程的能力。 一、什么是接口&#xff1f; 接口是一组方法签名的集合&#xff0c;任何类型只要实现了接口中声明的所有方法&#xff0c;就被视为实现了…

JSR 303(即 Bean Validation)是一个通过​​注解在 Java Bean 上定义和执行验证规则​​的规范

&#x1f6e0;️ 一、JSR 303是什么&#xff1f; JSR 303&#xff08;Java Specification Requests 303&#xff09;是Java EE 6的子规范&#xff0c;全称​​Bean Validation​​。它通过注解方式对JavaBean的属性值进行标准化校验&#xff0c;例如检查非空、长度、格式等规则…

【图像处理入门】3. 几何变换基础:从平移旋转到插值魔法

摘要 掌握图像的几何变换相当于学会「图像的空间魔法」。本文将带你理解平移/旋转/缩放的数学原理&#xff0c;掌握OpenCV中warpAffine和getAffineTransform的核心用法&#xff0c;对比最近邻、双线性等插值算法的优劣。通过图像翻转、镜像、透视变换实战&#xff0c;学会用变…

微信小程序学习目录

个人简介 &#x1f468;‍&#x1f4bb;‍个人主页&#xff1a; 魔术师 &#x1f4d6;学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全栈发展 &#x1f6b4;个人状态&#xff1a; 研发工程师&#xff0c;现效力于政务服务网事业 &#x1f1e8;&#x1f1f3;人生格言&…

QT 5.15.2 程序中文乱码

1. 在.pro文件中添加&#xff1a; msvc { QMAKE_CXXFLAGS /source-charset:utf-8 /execution-charset:utf-8 }备注&#xff1a;.pro文件只有在选择 qmake 方式才会生成。 [Cmake 只会生成 CMakeLists.txt 文件] 2. 在文件首部增加以下程序行 #pragma execution_character_s…

Unity UI设计优化与模式原则

前言 在 Unity 中设计高效且可维护的 UI 系统时&#xff0c;需要结合性能优化和设计模式两大核心方向。以下是关键原则及实践方法&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&#xff0c;希望大家可以点击进来一起交流一下开发经验呀&#xff01; 一、UI 性能…