news 2026/9/4 3:56:37

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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.publicclassMainimplementsSum{publicstaticvoidmain(String[]args){Mainm=newMain();m.sum();m.sum1();}@Deprecated// 不建议使用的注解publicvoidsum1(){System.out.println("nihao11111");}@Overridepublicvoidsum(){System.out.println("nihao");}}

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

1.1.1 @SuppressWarnings注解用法

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

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

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

Contentsof collection'items'are updated,but never queried
package蓝桥杯国赛刷题;importjava.util.ArrayList;importjava.util.List;publicclasscommentTest01{publicstaticvoidmain(String[]args){commentTest01CommentTest01=newcommentTest01();CommentTest01.addItems("1234");}publicvoidaddItems(Stringitem){Listitems=newArrayList();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作为默认值。

自定义注解样例:

//自定义注解publicclasstest03{//注解可以显示赋值, 如果没有默认值,我们就必须给注解赋值//注解参数的顺序随意@MyAnnotation2(age=18,name="jacky")publicvoidtest(){}@MyAnnotation3("jacky")publicvoidtest2(){}}@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@interfaceMyAnnotation2{//注解的参数: 参数类型 + 参数名 + ();Stringname()default"";intage()default0;intid()default-1;String[]schools()default{"peking university"};}@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@interfaceMyAnnotation3{//如果注解参数为value赋值时可以直接写值Stringvalue();}

在这个例子我们,我们定义了两个注解,分别是@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类型信息publicclassText02{publicstaticvoidmain(String[]args)throwsClassNotFoundException{//方式1:通过类名ClassstringClass1=String.class;//方式2:通过Class类的forName()方法ClassstringClass2=Class.forName("java.lang.String");//方式3:通过对象调用getClass()方法ClassstringClass3="".getClass();System.out.println(stringClass1.hashCode());//1604839423System.out.println(stringClass2.hashCode());//1604839423System.out.println(stringClass3.hashCode());//1604839423}}

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

//Class类型的对象使用场景1publicclassText03{publicstaticvoidmain(String[]args){Stringjson="{\"name\":\"长安荔枝\",\"favCount\":234}";Documentdoc=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//获取丰富的类型内容publicclassText04{publicstaticvoidmain(String[]args)throwsClassNotFoundException{Classclz=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(Fieldfield:fieldArray){System.out.println(field);}System.out.println();//获取成员方法Method[]methodArray=clz.getDeclaredMethods();System.out.println("成员方法");for(Methodmethod: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)来创建对象。

//通过反射的方式,创建对象publicclassText05{publicstaticvoidmain(String[]args)throwsClassNotFoundException,InstantiationException,IllegalAccessException,NoSuchMethodException,SecurityException,IllegalArgumentException,InvocationTargetException{Classclz=Class.forName("com.apesource.demo01.Document");//方式1:直接通过Class对象,调用newInstance()方法Objectobjx=clz.newInstance();//相当于在执行无参构造方法//方式2:通过构造器(构造方法)//无参构造方法Constructorconstructor1=clz.getDeclaredConstructor();//获取无参构造方法System.out.println(constructor1);Objectobj1=constructor1.newInstance();//执行构造器(构造方法),创建对象//有参构造方法Constructorconstructor2=clz.getDeclaredConstructor(String.class);//获取有参构造方法System.out.println(constructor2);Objectobj2=constructor2.newInstance("两京十五日");Constructorconstructor3=clz.getDeclaredConstructor(int.class);//获取有参构造方法System.out.println(constructor3);Objectobj3=constructor3.newInstance(34);Constructorconstructor4=clz.getDeclaredConstructor(String.class,int.class);//获取有参构造方法System.out.println(constructor4);Objectobj4=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 使用反射机制获取和调用类的构造方法,访问私有构造方法并创建对象

publicclassText06{publicstaticvoidmain(String[]args)throwsClassNotFoundException,NoSuchMethodException,SecurityException,InstantiationException,IllegalAccessException,IllegalArgumentException,InvocationTargetException{Classclz=Class.forName("com.apesource.demo01.Document");//获取一组构造器Constructor[]constructorArray1=clz.getConstructors();//publicConstructor[]constructorArray2=clz.getDeclaredConstructors();//public、private//获取指定构造器Constructorconstructor1=clz.getConstructor();Constructorconstructor2=clz.getDeclaredConstructor(String.class);System.out.println(constructor1);System.out.println(constructor2);//调用私有构造器,必须设置它的访问全限constructor2.setAccessible(true);//调用构造器,创建对象Objectobj=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 通过反射,访问并使用成员方法

publicclassText08{publicstaticvoidmain(String[]args)throwsClassNotFoundException,InstantiationException,IllegalAccessException,NoSuchMethodException,SecurityException,IllegalArgumentException,InvocationTargetException{//硬编码的方式// Document doc1 = new Document();// doc1.setName("海底两万里");// doc1.setFavCount(10025);//反射的方式Classclz=Class.forName("com.apesource.demo01.Document");//获取类型信息Objectdoc1=clz.newInstance();//创建对象//获取指定名称和参数类型的方法MethodsetNameMethod=clz.getMethod("setName",String.class);MethodsetFavCountMethod=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注解与反射的全部内容了,笔者编写不易,恳请点赞收藏,欢迎评论区交流!!!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/3 21:38:18

Python提取PDF表格:主流库对比与实战指南

PDF 表格提取&#xff0c;是 Python 技术社区里一个高频出现、但每次做都容易卡壳的需求。财务对账要读银行流水 PDF&#xff0c;数据分析师要整理年报中的财务报表&#xff0c;行政要从扫描版公告里摘录名单&#xff0c;开发者在 CSV 和 Excel 之外遇到这种“半结构化”数据源…

作者头像 李华
网站建设 2026/9/3 19:29:31

Czkawka 磁盘清理完整指南:从重复文件扫描到相似图片分组

Czkawka 磁盘清理完整指南&#xff1a;从重复文件扫描到相似图片分组 【免费下载链接】czkawka Multi functional app to find duplicates, empty folders, similar images etc. 项目地址: https://gitcode.com/GitHub_Trending/cz/czkawka 如果你的磁盘里散落着好几份同…

作者头像 李华
网站建设 2026/9/2 11:52:46

Grok Bot强制命名是优点:从身份标识到实例管理的工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 21:38:35

Python GUI开发:从事件驱动原理到Gradio与Streamlit实战应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 11:51:22

本地部署DeepSeek Harness,打造会说话的AI角色“爱莉”

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 11:51:11

求生之路2三方图浪潮狂疫:安装、联机与高难度团队生存指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华