Java中的@interface以及method.invoke()
来源:互联网 发布:课程顾问 知乎 编辑:程序博客网 时间:2024/05/29 13:00
前言
这几天在看暑假要去实习的公司的框架源码,该框架十分轻量级,上手贼快。
Web容器是Jetty
,数据库是MySQL
,使用该框架形式为插件开发,只需要按照该框架可以识别的规则开发,再将项目放到指定目录下,服务启动后加载该目录下的所有插件,用反射进行方法调用(几乎所有的框架底层都是用反射的吧)。
看了一天过后对框架整体有了一定了解,但是之前自己没有写过相关的代码,因此写了几个小demo进行测试,今天谈一谈Java中的注解和反射。
method.invoke()
反射的概念不再赘述,直接来说method.invoke()
的使用。
查看源代码如下:
@CallerSensitivepublic Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { // Object...表示参数为0到多个 if (!override) { if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) { Class<?> caller = Reflection.getCallerClass(); checkAccess(caller, clazz, obj, modifiers); } } MethodAccessor ma = methodAccessor; // read volatile if (ma == null) { ma = acquireMethodAccessor(); } return ma.invoke(obj, args);}
不深究源代码的意义,我们只来看参数,obj
是该方法对应的类的对象,如果该方法是一个静态方法,obj
参数可以为null
;args
为该方法需要传入的参数,这里Object...
表示参数为0到多个。如果要调用的方法没有参数,就传入参数。如果方法是void
方法,那么返回null
;如果方法返回类型是基本类型,返回基本类型的包装类。
接下来来看demo:
Demo
测试的类为:
public class InvokeObject { public InvokeObject() { System.out.println("这是构造方法"); } public void print() { System.out.println("这是无参方法"); } public void print(String str) { System.out.println("这是有一个参数的方法,传入的参数为:" + str); } public void print(String str1, String str2) { System.out.println("这是有一个参数的方法,传入的参数str1为:" + str1 + ",str2为:" + str2); }}
测试方法为:
import java.lang.reflect.Method;public class Main { @SuppressWarnings("rawtypes") public static void main(String[] args) throws Exception { Class<InvokeObject> clazz = InvokeObject.class; Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { // 方法的返回值类型 Class returnType = method.getReturnType(); System.out.print(returnType.getName() + " "); // 方法的名字 System.out.print(method.getName() + " ("); // 获取参数类型 Class[] paramsType = method.getParameterTypes(); StringBuilder param = new StringBuilder(); for (Class class1 : paramsType) { param.append(class1.getName() + ", "); } if (param.length() > 1) { param.delete(param.length() - 2, param.length()); } System.out.print(param.toString()); System.out.println(")"); } Method method = clazz.getMethod("print"); method.invoke(null); // 注意这里穿的参数为null }}
执行的结果如下:
void print (java.lang.String, java.lang.String)void print (java.lang.String)void print ()Exception in thread "main" java.lang.NullPointerException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at cn.alone.Reflect.Main.main(Main.java:31)
因为在invoke方法中传入了空参数,而且调用的方法不是静态方法,所以会报错,如果我们将无参的print方法设为static的或者传入一个InvokeObject对象,就会输出下面的结果:
void print (java.lang.String, java.lang.String)void print (java.lang.String)void print ()这是构造方法这是无参方法
再次修改测试代码:
import java.lang.reflect.Method;public class Main { @SuppressWarnings("rawtypes") public static void main(String[] args) throws Exception { Class<InvokeObject> clazz = InvokeObject.class; Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { // 方法的返回值类型 Class returnType = method.getReturnType(); System.out.print(returnType.getName() + " "); // 方法的名字 System.out.print(method.getName() + " ("); // 获取参数类型 Class[] paramsType = method.getParameterTypes(); StringBuilder param = new StringBuilder(); for (Class class1 : paramsType) { param.append(class1.getName() + ", "); } if (param.length() > 1) { param.delete(param.length() - 2, param.length()); } System.out.print(param.toString()); System.out.println(")"); } Method method = clazz.getMethod("print"); method.invoke(clazz.newInstance()); Method method1 = clazz.getMethod("print", String.class); // 获得参数为String,方法名为print的方法 method1.invoke(clazz.newInstance(), "一个参数"); Method method2 = clazz.getMethod("print", String.class, String.class); method2.invoke(clazz.newInstance(), "第一个参数", "第二个参数"); }}
执行结果如下:
void print (java.lang.String, java.lang.String)void print (java.lang.String)void print ()这是构造方法这是无参方法这是构造方法这是有一个参数的方法,传入的参数为:一个参数这是构造方法这是有一个参数的方法,传入的参数str1为:第一个参数,str2为:第二个参数
@interface
注解
Java中用@interface
来定义一个注解Annotation
,程序中使用注解也就是对注解的程序做了一个标记,之后就可以用反射来找到标记的程序,进而进行一些操作。
我们熟悉的JDK自带的注解有@Override
、@Deprecated
等,大名鼎鼎的Spring
生态中各种注解让我们十分方便快捷地进行开发。
@Retention
元注解
注解@Retention
可以用来修饰注解,是注解的注解,称为元注解。查看源码(JDK1.8):
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value();}
继续查看RetentionPolicy
的源码:
public enum RetentionPolicy { /** * Annotations are to be discarded by the compiler. */ SOURCE, /** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior. */ CLASS, /** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, so they may be read reflectively. * * @see java.lang.reflect.AnnotatedElement */ RUNTIME}
也就是说@Retention
元注解需要传入一个参数value,有3种,分别为SOURCE
、CLASS
、RUNTIME
,他们的意义如下:
用@Retention(RetentionPolicy.CLASS)修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,但不会被虚拟机读取在运行的时候;
用@Retention(RetentionPolicy.SOURCE )修饰的注解,表示注解的信息会被编译器抛弃,不会留在class文件中,注解的信息只会留在源文件中;
用@Retention(RetentionPolicy.RUNTIME )修饰的注解,表示注解的信息被保留在class文件(字节码文件)中当程序编译时,会被虚拟机保留在运行时。Java注释@interface的用法
@Target
元注解
@Target
也是一个元注解,这个元注解用来表明要标识的注解可以对什么进行注解,@Target
的value
有以下几种:
public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, /** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Formal parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE, /** * Type parameter declaration * * @since 1.8 */ TYPE_PARAMETER, /** * Use of a type * * @since 1.8 */ TYPE_USE}
@Target(value)
中的value
可以有多个,如@Target({ElementType.FIELD, ElementType.METHOD})
。
Demo
定义一个注解:
@Retention(RetentionPolicy.RUNTIME) // 注解的信息保存在class文件中public static @interface MyMethod { // 注解内部可以指定注解属性}
在InvokeObject的方法上加上注解:
public class InvokeObject { public InvokeObject() { System.out.println("这是构造方法"); } @MyMethod public void print() { System.out.println("这是无参方法"); } @MyMethod public void print(String str) { System.out.println("这是有一个参数的方法,传入的参数为:" + str); } public void print(String str1, String str2) { System.out.println("这是有一个参数的方法,传入的参数str1为:" + str1 + ",str2为:" + str2); }}
Main方法用来测试:
import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.reflect.Method;import cn.alone.Reflect.InvokeObject;public class MyAnnotation { @Retention(RetentionPolicy.RUNTIME) // 注解的信息保存在class文件中 public static @interface MyMethod { } public static void main(String[] args) throws NoSuchMethodException, SecurityException, Exception, Exception, Exception { Method method = InvokeObject.class.getMethod("print"); // 获得方法名为print的无参方法 if (method.isAnnotationPresent(MyMethod.class)) { // 如果是MyMethod注解标记的方法,返回true method.invoke(new InvokeObject()); } }}
执行结果如下:
这是构造方法这是无参方法
获取一个参数的方法:
public static void main(String[] args) throws NoSuchMethodException, SecurityException, Exception, Exception, Exception { Method method = InvokeObject.class.getMethod("print", String.class); // 获得参数为String,方法名为print的方法 if (method.isAnnotationPresent(MyMethod.class)) { // 如果是MyMethod注解标记的方法,返回true method.invoke(new InvokeObject(), "一个参数"); }}
执行结果如下:
这是构造方法这是有一个参数的方法,传入的参数为:一个参数
如果获取3个参数的方法呢?
public static void main(String[] args) throws NoSuchMethodException, SecurityException, Exception, Exception, Exception { Method method = InvokeObject.class.getMethod("print", String.class, String.class); // 获得参数为String,方法名为print的方法 if (method.isAnnotationPresent(MyMethod.class)) { // 如果是MyMethod注解标记的方法,返回true method.invoke(new InvokeObject(), "第一个参数", "第二个参数"); }}
执行结果什么都没有输出。
结语
通过简单的Demo,了解的Java中注解的基本使用,以及反射调用类方法的基本用法。
- Java中的@interface以及method.invoke()
- Java反射机制 以及 method.invoke运用
- java反射机制以及Method.invoke解释
- java中的反射--method的invoke方法
- java 反射中的method.invoke()方法详解
- Method 中的 invoke()
- java method invoke
- Attempt to invoke interface method 'java.lang.Object[] java.util.Collection.toArray()' on a null obj
- Invoke interface method 'java.lang.Object[]java.util.Collection.toArray()'on a null object reference
- Attempt to invoke interface method 'boolean java.util.List.add(java.lang.Object)' on a null
- java class.forname method.invoke
- java Method invoke 参数问题
- java.lang.RuntimeException: invoke method
- 错误:Attempt to invoke interface method 'boolean java.util.List.add(java.lang.Object)' on a null
- method.invoke
- Method invoke
- java反射中method类中的invoke方法是做什么的,他有什么作用?
- java反射Method中的如何调用任意方法,即invoke()的使用
- 安卓Binder
- 装饰器模式
- 设计模式二之工厂方法
- SEH 进阶(2)
- 简单描述JSON跟JSONP的区别以及实战
- Java中的@interface以及method.invoke()
- 日志统计redis和mongo对比
- 面试题27:二叉搜索树与双向链表
- 【标题】:密文搜索
- 最安全的单例模式--java使用内部类实现单例模式
- mongodb的一些经验值
- 冒泡排序与选择拍序
- Jpush之如何利用HttpClient实现消息推送到手机
- 一般导入的包有问题