公司动态
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 bRun/b code, press shortcut actionIdRun/ or// click the icon srcAllIcons.Actions.Execute/ icon in the gutter.publicclassMainimplementsSum{publicstaticvoidmain(String[]args){MainmnewMain();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 collectionitemsare updated,but never queriedpackage蓝桥杯国赛刷题;importjava.util.ArrayList;importjava.util.List;publicclasscommentTest01{publicstaticvoidmain(String[]args){commentTest01CommentTest01newcommentTest01();CommentTest01.addItems(1234);}publicvoidaddItems(Stringitem){ListitemsnewArrayList();items.add(item);}}1.2 元注解元注解的作用就是负责注解其他注解Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明这些类型和它们所支持的类在java.lang.annotation包中可以找到分别是Target,Retention,Documented,lnheritedTarget用于描述注解的使用范围(即被描述的注解可以用在什么地方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(age18,namejacky)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:通过类名ClassstringClass1String.class;//方式2通过Class类的forName()方法ClassstringClass2Class.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};DocumentdocJSON.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{ClassclzClass.forName(java.util.HashMap);//获取类名System.out.println(完全限定名clz.getName());System.out.println(简单的类名clz.getSimpleName());//获取包名System.out.println(packageclz.getPackage().getName());System.out.println();//获取成员变量Field[]fieldArrayclz.getDeclaredFields();System.out.println(成员变量(字段));for(Fieldfield:fieldArray){System.out.println(field);}System.out.println();//获取成员方法Method[]methodArrayclz.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{ClassclzClass.forName(com.apesource.demo01.Document);//方式1直接通过Class对象调用newInstance()方法Objectobjxclz.newInstance();//相当于在执行无参构造方法//方式2通过构造器(构造方法)//无参构造方法Constructorconstructor1clz.getDeclaredConstructor();//获取无参构造方法System.out.println(constructor1);Objectobj1constructor1.newInstance();//执行构造器(构造方法),创建对象//有参构造方法Constructorconstructor2clz.getDeclaredConstructor(String.class);//获取有参构造方法System.out.println(constructor2);Objectobj2constructor2.newInstance(两京十五日);Constructorconstructor3clz.getDeclaredConstructor(int.class);//获取有参构造方法System.out.println(constructor3);Objectobj3constructor3.newInstance(34);Constructorconstructor4clz.getDeclaredConstructor(String.class,int.class);//获取有参构造方法System.out.println(constructor4);Objectobj4constructor4.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{ClassclzClass.forName(com.apesource.demo01.Document);//获取一组构造器Constructor[]constructorArray1clz.getConstructors();//publicConstructor[]constructorArray2clz.getDeclaredConstructors();//public、private//获取指定构造器Constructorconstructor1clz.getConstructor();Constructorconstructor2clz.getDeclaredConstructor(String.class);System.out.println(constructor1);System.out.println(constructor2);//调用私有构造器必须设置它的访问全限constructor2.setAccessible(true);//调用构造器创建对象Objectobjconstructor2.newInstance(长安三万里);System.out.println(obj);}}getConstructors()方法返回一个包含所有公共public构造方法的数组。如果类中没有public构造方法则返回空数组。getDeclaredConstructors()方法返回一个包含所有声明的构造方法的数组包括私有的、受保护的和默认访问级别的构造方法。getConstructor()方法用于获取类的无参构造方法必须是public的。如果没有无参构造方法或者不是public则抛出NoSuchMethodException。getDeclaredConstructor(Class?... parameterTypes)方法用于获取指定参数类型的构造方法。这里通过传入String.class参数获取一个带有String参数的构造方法。这个构造方法可以是任何访问级别public、private、protected、默认。setAccessible(true)用于绕过 Java 访问控制机制使私有构造方法也可以被调用。如果不设置Accessible为true那么调用私有构造方法时会抛出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);//反射的方式ClassclzClass.forName(com.apesource.demo01.Document);//获取类型信息Objectdoc1clz.newInstance();//创建对象//获取指定名称和参数类型的方法MethodsetNameMethodclz.getMethod(setName,String.class);MethodsetFavCountMethodclz.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注解与反射的全部内容了笔者编写不易恳请点赞收藏欢迎评论区交流