当前位置: 首页 > news >正文

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注解与反射的全部内容了,笔者编写不易,恳请点赞收藏,欢迎评论区交流!!!

相关文章:

  • React从基础入门到高级实战:React 生态与工具 - React 国际化(i18n)
  • Mac系统下,利用wget批量下载ICESat-2测高内陆水位高数据ALT13
  • SpringBoot整合RocketMQ--实例
  • RTX腾讯通停服后,有哪些兼容Linux及移动端的升级途径?
  • SQL(Database Modifications)
  • 杏仁海棠花饼的学习日记第十四天CSS
  • Windows 11 全角半角切换方法
  • 《仿盒马》app开发技术分享-- 订单列表页(端云一体)
  • 日常--OBS+mediamtx实现本地RTMP推流环境搭建(详细图文)
  • Telegram平台分发其聊天机器人Grok
  • 【仿生系统】爱丽丝的“内在”或“灵魂”:概念与形式
  • 关于《DAHSF》即《火小兔智慧开发平台V2.0》的碎碎念
  • 微机系统-汇编语言入门
  • 计算机图形学:(六)渲染管线
  • 基于matlab遗传算法和模拟退火算法求解三维装箱优化问题
  • Virtuoso中对GDS文件进行工艺库转换的方法
  • Vision Transformer网络结构
  • CppCon 2014 学习第4天:Transactional Language Constructs for C++ TS(未进入到标准)
  • 麒麟v10+信创x86处理器离线搭建k8s集群完整过程
  • 【实证分析】上市公司全要素生产率+5种测算方式(1999-2024年)
  • php做网站怎么布局/设计网页
  • 984网站建设项目/产品质量推广营销语
  • 邯郸网站建设选哪家/yahoo引擎入口
  • 微信商城网站模板/哈尔滨企业网站模板建站
  • 中国建设银行总行门户网站/怎么接广告赚钱
  • 自做购物网站多少钱/蜜雪冰城推广软文