Java反射机制,Java注解,利用Java反射调用类方法,自定义Java注解
2016-12-07 19:50
806 查看
一、反射
在了解JAVA反射机制以前,首先要了解类是什么,对象是什么!
1.1 万事万物皆对象
任何一个类都是Java.Lang.Class类的实例对象,任何一个实例对象有三种表示方式:
1.2 Class类
Class.forName("类的全称")
不仅表示了类的类类型,还代表了动态加载类;
区分编译,运行,编译时刻加载类是静态加载类,运行时刻加载类的动态加载类;
new 创建对象是静态加载类,在编译时就需要加载所有的可能使用到的类;
通过动态加载类可以实现用到类时再加载类,即运行时再加载类
注意:基本的数据类型和void关键字,都存在类类型
1.3 Class 类的基本API操作
首先要知道,Method、Field、Constructor,都是对象
//打印类的信息,包括类的成员函数,成员变量
* getMethods()获取的是该类所有的public函数,包括从父类继承而来的
* getMethod(MethodName)通过方法名获取方法
* getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限
* getReturnType()获取方法的返回值类型的类类型
* getParameterTypes()得到参数列表的类型的类类型
*
getDeclaredFields()获取的是该类自己声明的成员变量的信息
输出的是String类的所有public方法和参数。
1.4 通过反射实现调用方法
必须要获取类的信息,首先要获取类的类类型,再通过获取到的方法,利用反射来调用方法
* getMethods()获取的是public的所有方法
* getDeclaredMethos()获取的是该类自己申明的方法
or
方法的反射操作 反射的操作都是编译之后的操作
m.invoke(a1,20,30);
or
m.invoke(a1,object[]{20,30});
注意:泛型经过编译之后是去泛型化的,JAVA中集合的泛型,是防止错误,只在编译阶段有效,编译之后就无泛型了。
验证:通过方法的反射来操作,可以绕过编译直接运行
二、JAVA注解
Java提供的一种原程序中的元素关联任何信息和任何数据的途径和方法
定义:
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
作用分类:
①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
② 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
2.1 JDK自带注解
@Override(重写父类方法)
子类重写父类方法时,方法的上面都会出现这个注解
@Deprecated(方法已经过时)
如果一定要用这个过时的方法呢,可以使用@Suppvisewarnings("deprecation")忽视这个错误
@Suppvisewarnings
可以用来声明忽视某个错误
2.2 常用第三方注解
Spring: @Autowired @Service @Repository
Mybatis: @InsertProvider @UpdateProvider @Options
2.3 注解的分类
按运行机制:
源码注解:注解只在源码中存在,编译在.class文件之后就不存在了;
编译注解:注解在源码和.class文件中都存在;
运行注解:在运行阶段还起作用,甚至会影响运行逻辑的注解;
按来源:
来自JDK的注解
来自第三方的注解
自定义的注解
元注解:是注解的注解
2.4 自定义注解
Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。
注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。
2.4.1、元注解
元注解是指注解的注解。包括 @Retention @Target @Document @Inherited四种。
2.4.1.1、@Retention: 定义注解的保留策略
@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
2.4.1.2、@Target:定义注解的作用目标
其定义的源码为:
由以上的源码可以知道,他的elementType 可以有多个,一个注解可以为类的,方法的,字段的等等
作用目标有以下几种:
@Target(ElementType.TYPE) //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包
举例:
@Retention(RetentionPolicy.RUNTIME)
定义的这个注解是运行时注解,在class字节码文件中存在,在运行时可以通过反射获取到。
@Target({ElementType.TYPE,ElementType.METHOD})
因此这个注解可以是类注解,也可以是方法的注解
2.4.1.3、@Document:说明该注解将被包含在javadoc中
2.4.1.4、@Inherited:说明子类可以继承父类中的该类的注解,而方法的注解是不会继承的(只有在继承类的时候才可以,接口不可以)
2.4.2、java 注解的自定义
下面是自定义注解的一个例子
(1)首先自定义两种注解,当然注解里面的成员可以为基本的数据类型,也可以为数据,Object等等
@Yts
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.*;
@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Yts {
public enum YtsType{util,entity,service,model}
public YtsType classType() default YtsType.util;
}
@HelloWorld
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface HelloWorld {
public String name()default "";
}
(2)注解是定义好了,那么怎么来得到,解析注解呢?
解析注解:通过反射获取类,函数或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ParseAnnotation {
//解析得到方法的注解
public void parseMethod(Class clazz) throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException, SecurityException, NoSuchMethodException, InstantiationException {
@SuppressWarnings("unchecked")
Object obj = clazz.getConstructor(new Class[] {}).newInstance(new Object[] {});//通过类的构造方法实例化对象
for (Method method : clazz.getDeclaredMethods()) {//获取类自己声明的方法
HelloWorld say = method.getAnnotation(HelloWorld.class);
String name = "";
if (say != null) {
name = say.name();
method.invoke(obj, name);
}
Yts yts = (Yts) method.getAnnotation(Yts.class);
if (yts != null) {
if (Yts.YtsType.util.equals(yts.classType())) {
System.out.println("this is a util method");
} else {
System.out.println("this is a other method");
}
}
}
}
//解析得到类的注解
@SuppressWarnings("unchecked")
public void parseType(Class clazz)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Yts yts = (Yts) clazz.getAnnotation(Yts.class);
if (yts != null) {
if (Yts.YtsType.util.equals(yts.classType())) {
System.out.println("this is a util class");
} else {
System.out.println("this is a other class");
}
}
}
//主函数
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, InstantiationException {
ParseAnnotation parse = new ParseAnnotation();
parse.parseMethod(SayHell.class);
parse.parseType(SayHell.class);
}
}
//以下是测试方法类
@Yts(classType = Yts.YtsType.util)
class SayHell {
@HelloWorld(name = " 小明 ")
@Yts
public void sayHello(String name) {
if (name == null || name.equals("")) {
System.out.println("hello world!");
} else {
System.out.println(name + "say hello world!");
}
}
public SayHell() {
System.out.println("hell");
}
}
得到的结果:
这里是构造方法:SayHell
小明 say hello world!
this is a util method
this is a util class
在了解JAVA反射机制以前,首先要了解类是什么,对象是什么!
1.1 万事万物皆对象
任何一个类都是Java.Lang.Class类的实例对象,任何一个实例对象有三种表示方式:
public class reflectDemo { public static void main(String[] args) throws ClassNotFoundException { foo foo1 = new foo(); //1、任何一个类都一个隐含的静态成员变量class Class c1 = foo.class; //2、 通过实例化对象的getClass()方法获得该对象的类 Class c2 = foo1.getClass(); //c1,c2都代表了foo类的类类型 System.out.println(c1 == c2);//输出true //3、使用Class.forName()方法获取类的类类型 Class c3 = null; c3 = Class.forName("foo"); System.out.println(c2 == c3);//输出true System.out.println(c2+":"+c3);//输出"class foo:class foo" //可以通过类的类类型创建foo类的对象实例 try { foo foo2 = (foo) c1.newInstance(); System.out.println(foo2.getClass());//输出"class foo" } catch (InstantiationException | IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } class foo{ }
1.2 Class类
Class.forName("类的全称")
不仅表示了类的类类型,还代表了动态加载类;
区分编译,运行,编译时刻加载类是静态加载类,运行时刻加载类的动态加载类;
new 创建对象是静态加载类,在编译时就需要加载所有的可能使用到的类;
通过动态加载类可以实现用到类时再加载类,即运行时再加载类
注意:基本的数据类型和void关键字,都存在类类型
Class c1 = int.class; Class c2 = Integer.class; Class c3 = String.class; Class c4 = void.class; System.out.println(c1+":"+c2); System.out.println(c3+":"+c4); 输出: int:class java.lang.Integer class java.lang.String:void
1.3 Class 类的基本API操作
首先要知道,Method、Field、Constructor,都是对象
//打印类的信息,包括类的成员函数,成员变量
* getMethods()获取的是该类所有的public函数,包括从父类继承而来的
* getMethod(MethodName)通过方法名获取方法
* getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限
* getReturnType()获取方法的返回值类型的类类型
* getParameterTypes()得到参数列表的类型的类类型
*
getDeclaredFields()获取的是该类自己声明的成员变量的信息
import java.lang.reflect.Method; public class reflectDemo { public static void main(String[] args) throws ClassNotFoundException { getClassMessages("Test.java");//可以获取所有String类的方法名称,方法参数 } public static void getClassMessages(Object obj){ //要获取类的信息,首先要获取类的类类型, Class c = obj.getClass();//传递的是哪个子类的对象,c就该子类的类类型 //获取类的名称 System.out.println("类的名称:"+c.getName()); /* * Method类,方法对象 * 一个成员方法就是一个Method对象 * getMethods()获取的是该类所有的public函数,包括从父类继承而来的 * getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限 */ Method[] ms = c.getMethods(); for (int i = 0; i < ms.length; i++) { //得到方法的返回值类型的类类型 Class returnType = ms[i].getReturnType(); System.out.print(returnType.getName()+" "); //获取方法的名称 System.out.print(ms[i].getName()+"("); //获取方法的参数类型,得到的是参数列表的类型的类类型 Class[] parameterTypes = ms[i].getParameterTypes(); for(Class class1:parameterTypes){ System.out.print(class1.getName()+","); } System.out.print(")\n"); } } }
输出的是String类的所有public方法和参数。
1.4 通过反射实现调用方法
必须要获取类的信息,首先要获取类的类类型,再通过获取到的方法,利用反射来调用方法
* getMethods()获取的是public的所有方法
* getDeclaredMethos()获取的是该类自己申明的方法
A a1 = new A(); Method m = getMethod("print",Class[]{int.class,int.class});
or
Method m = getMethod("print",int.class,int.class);
方法的反射操作 反射的操作都是编译之后的操作
m.invoke(a1,20,30);
or
m.invoke(a1,object[]{20,30});
注意:泛型经过编译之后是去泛型化的,JAVA中集合的泛型,是防止错误,只在编译阶段有效,编译之后就无泛型了。
验证:通过方法的反射来操作,可以绕过编译直接运行
二、JAVA注解
Java提供的一种原程序中的元素关联任何信息和任何数据的途径和方法
定义:
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
作用分类:
①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
② 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
2.1 JDK自带注解
@Override(重写父类方法)
子类重写父类方法时,方法的上面都会出现这个注解
@Deprecated(方法已经过时)
如果一定要用这个过时的方法呢,可以使用@Suppvisewarnings("deprecation")忽视这个错误
@Suppvisewarnings
可以用来声明忽视某个错误
2.2 常用第三方注解
Spring: @Autowired @Service @Repository
Mybatis: @InsertProvider @UpdateProvider @Options
2.3 注解的分类
按运行机制:
源码注解:注解只在源码中存在,编译在.class文件之后就不存在了;
编译注解:注解在源码和.class文件中都存在;
运行注解:在运行阶段还起作用,甚至会影响运行逻辑的注解;
按来源:
来自JDK的注解
来自第三方的注解
自定义的注解
元注解:是注解的注解
2.4 自定义注解
Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。
注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。
2.4.1、元注解
元注解是指注解的注解。包括 @Retention @Target @Document @Inherited四种。
2.4.1.1、@Retention: 定义注解的保留策略
@Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得,
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到
2.4.1.2、@Target:定义注解的作用目标
其定义的源码为:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
由以上的源码可以知道,他的elementType 可以有多个,一个注解可以为类的,方法的,字段的等等
作用目标有以下几种:
@Target(ElementType.TYPE) //接口、类、枚举、注解
@Target(ElementType.FIELD) //字段、枚举的常量
@Target(ElementType.METHOD) //方法
@Target(ElementType.PARAMETER) //方法参数
@Target(ElementType.CONSTRUCTOR) //构造函数
@Target(ElementType.LOCAL_VARIABLE)//局部变量
@Target(ElementType.ANNOTATION_TYPE)//注解
@Target(ElementType.PACKAGE) ///包
举例:
@Retention(RetentionPolicy.RUNTIME)
定义的这个注解是运行时注解,在class字节码文件中存在,在运行时可以通过反射获取到。
@Target({ElementType.TYPE,ElementType.METHOD})
因此这个注解可以是类注解,也可以是方法的注解
2.4.1.3、@Document:说明该注解将被包含在javadoc中
2.4.1.4、@Inherited:说明子类可以继承父类中的该类的注解,而方法的注解是不会继承的(只有在继承类的时候才可以,接口不可以)
2.4.2、java 注解的自定义
下面是自定义注解的一个例子
(1)首先自定义两种注解,当然注解里面的成员可以为基本的数据类型,也可以为数据,Object等等
@Yts
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.*;
@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Yts {
public enum YtsType{util,entity,service,model}
public YtsType classType() default YtsType.util;
}
@HelloWorld
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface HelloWorld {
public String name()default "";
}
(2)注解是定义好了,那么怎么来得到,解析注解呢?
解析注解:通过反射获取类,函数或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ParseAnnotation {
//解析得到方法的注解
public void parseMethod(Class clazz) throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException, SecurityException, NoSuchMethodException, InstantiationException {
@SuppressWarnings("unchecked")
Object obj = clazz.getConstructor(new Class[] {}).newInstance(new Object[] {});//通过类的构造方法实例化对象
for (Method method : clazz.getDeclaredMethods()) {//获取类自己声明的方法
HelloWorld say = method.getAnnotation(HelloWorld.class);
String name = "";
if (say != null) {
name = say.name();
method.invoke(obj, name);
}
Yts yts = (Yts) method.getAnnotation(Yts.class);
if (yts != null) {
if (Yts.YtsType.util.equals(yts.classType())) {
System.out.println("this is a util method");
} else {
System.out.println("this is a other method");
}
}
}
}
//解析得到类的注解
@SuppressWarnings("unchecked")
public void parseType(Class clazz)
throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Yts yts = (Yts) clazz.getAnnotation(Yts.class);
if (yts != null) {
if (Yts.YtsType.util.equals(yts.classType())) {
System.out.println("this is a util class");
} else {
System.out.println("this is a other class");
}
}
}
//主函数
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException, InstantiationException {
ParseAnnotation parse = new ParseAnnotation();
parse.parseMethod(SayHell.class);
parse.parseType(SayHell.class);
}
}
//以下是测试方法类
@Yts(classType = Yts.YtsType.util)
class SayHell {
@HelloWorld(name = " 小明 ")
@Yts
public void sayHello(String name) {
if (name == null || name.equals("")) {
System.out.println("hello world!");
} else {
System.out.println(name + "say hello world!");
}
}
public SayHell() {
System.out.println("hell");
}
}
得到的结果:
这里是构造方法:SayHell
小明 say hello world!
this is a util method
this is a util class
相关文章推荐
- Java注解教程:自定义注解示例,利用反射进行解析
- Java注解教程:自定义注解示例,利用反射进行解析
- Java注解教程:自定义注解示例,利用反射进行解析
- Java注解教程:自定义注解示例,利用反射进行解析
- Java注解详解,自定义注解,利用反射解析注解
- 利用java反射调用类的的私有方法
- Java注解教程:自定义注解示例,利用反射进行解析
- Java注解教程:自定义注解示例,利用反射进行解析
- java 利用反射完成自定义注解
- Java注解教程:自定义注解示例,利用反射进行解析
- 利用java反射调用类的的私有方法
- 利用java反射调用类的的私有方法
- Java注解教程:自定义注解示例,利用反射进行解析
- Java注解教程:自定义注解示例,利用反射进行解析
- 利用java反射调用类的的私有方法
- Java注解教程:自定义注解示例,利用反射进行解析
- 利用java反射调用类及父类的的私有方法
- Java 自定义注解及利用反射读取注解
- 利用java反射调用类的的私有方法
- Java利用自定义注解、反射实现简单BaseDao实例