1.注解的支持
Java从1.5开始使用注解,在1.5及更高的Java版本中都可以使用注解。
2.Java内置注解
Java在1.5中内置了三种标准注解,这三中注解分别为:
@Override:表示当前方法将会覆盖超类(父类)中的该方法。
@Deprecated:该注解表示,使用了该注解的方法是不被赞成使用的,在编译器中使用带有该注解的方法时将会出现提示(方法名称中间会有一个中划线)。
@SuppressWarnings:该注解会关闭编译器的不正当禁告。
3.编写注解要使用的注解——————元注解
Java专门提供了四种注解来让我们编写新的注解,这四个注解被称为元注解,这四种注解为:
@Documented:该注解表示新编写的注解是否包含在JavaDoc文档中,没有参数,添加该注解,在导出javadoc文档时回将该注解导出到javadoc文档中。
@Inherited:该注解表示本注解是否允许被它的子类所继承。
@Target:表示注解使用的地方,对注解进行使用限制,该注解有参数,参数的取值为ElementType的静态常量值,取值可以有多个,多个的写法为 @Target({ElementType.FIELD,ElementType.TYPE})格式。
ElementType的静态常量值有:
CONSTRUCTOR:构造器声明。
FIELD:域的声明(包括 enum的实例)。
LOCAL_VARIABLE:局部变声明。
PACKAGE:包声明。
PARAMETER:参数声明。
TYPE:类、接口(包括注解类型)或enum声明。
@Retention:该注解表示此注解的保存级别,表示什么时候该注解将被抛弃,该注解有参数,参数的取值为RetentionPolicy的静态常量值,该注解不允许多取值,只允许有一个值。
RetentionPolicy的静态常量值有:
SOURCE:表示该注解只会在源代码文件中存在,编译成class文件时将被抛弃。
CLASS:表示该注解在class文件中将存在,在加载到VM中时将被抛弃。
RUNTIME:在VM中将保存该注解,在程序运行时可以通过反射的方式来获取注解的信息。
4.注解的编写方式:
注解的编写方式类似于接口的编写方式,只是要在interface关键字的前面加上@符号即可,然后在上方注解需要的元注解信息,
注解的参数编写方式:参数可以是单个,也可以有多个。也可以没有参数。如果一个参数需要同时有多个取值,则需要将该注解定义为数组的形式。声明参数时,参数后面必须要带有括号。示例如下:
ElementType.TYPE) (RetentionPolicy.RUNTIME) (public@interfaceController { Stringvalue() default""; String[] type() ; }
5.反射获取注解信息
如果注解的@Retention注解的取值为RetentionPolicy.RUNTIME,则在程序运行时可以通过反射的方式来获取注解的信息。
在项目运行时,我们可以使用类的全限定名(包名+"."+类名)来反射得到类对象。
然后通过类对象的isAnnotationPresent方法根据注解类的class来判断该类是否有特定的注解,如果有我们特定的注解,则可以通过类对象的getAnnotation方法根据注解类的class来获取该注解类的对象实例,然后使用注解类对象实例的参数来获取注解的参数值。
示例代码:
Class<?>clazz=Class.forName("com.jack.controller.CustomerController");//根据类的全限定名获取类对象。if(clazz.isAnnotation(Controller.class)){ //判断该类中是否有Controller注解。Controllercon=clazz.getAnnotation(Controller.class);//根据类的class来获取类的对象。Stringvalue=con.value(); String[] type=con.type(); }
6.反射说明
在Java中可以通过反射的方法来获取Java的类对象和类对象中的属性以及方法。
第一步:根据类的全限定名(包名+"."+类名)来获取类的class对象。
Class<?>clazz=Class.forName("com.jack.controller.CustomerController");
第二步:根据类的class对象获取类的实例。
Objectobject=clazz.newInstance();
第三步:根据class对象获取类的构造方法。
// 1.获取该类的全部构造方法Constructor<?>[] constructor=object.getClass().getDeclaredConstructors(); //2.根据构造方法的参数类型来获取指定的构造方法。//获取空构造Constructor<?>constructor2=clazz.getDeclaredConstructor(); //获取只有一个String类型的参数的构造方法。Constructor<?>constructor2=clazz.getDeclaredConstructor(String.class);
第四步:根据class对象获取该类的方法。
//1.获取该类的全部方法Method[] methods=clazz.getDeclaredMethods(); //2.根据方法的名称和参数类型来获取指定的方法。//第一个参数为方法的名称,第二个参数为可变参数,接受方法的参数类型的class对象。Methodmethod=clazz.getDeclaredMethod("sayHello", null);
第五步:根据class对象获取类的成员变量。
//1.获取该类的所有成员变量Field[] fieldss=clazz.getDeclaredFields(); //2.根据成员变量的名称来获取指定的成员变量。Fieldfieldss=clazz.getDeclaredFields(变量名称);
第六步:类的实例化
使用第二步的方法实例化类的时候要求类必须要有一个无参构造方法,如果该类没有无参构造方法,则必须先根据class对象获取 该类的所有构造方法,或者获取特定的构造方法,然后使用构造方法来实例化该对象。
Constructor<?>constructor2=clazz.getDeclaredConstructor(String.class); Objectobject=constructor2.newInstance(String类型的变量值);
第七步:给成员变量赋值。
获取到成员变量后可以给成员变量赋值。赋值使用成员变量Field的set方法来进行,set方法接受两个参数,第一个参数为该变量所在的类的对象,第二个参数为你要赋值的值,如果该成员变量时是私有的,那么在赋值之前必须要对该成员变量设置为支持赋值,该操作只需要设置该成员变量的setAccessible方法为true即可。
//1.获取类对象Objectobject=clazz.newInstance(); //2.根据成员变量名称获取指定的成员变量。Fieldfield=clazz.getDeclaredField(成员变量名称); //3.设置成员变量可赋值field.setAccessible(true); //4.给该成员变量赋值field.set(obj,要赋值给变量的值)。
第八步:对象方法的调用。
通过class对象拿到该类所有的方法之后,可以通过调用方法的invoke方法来执行该方法,该方法有两个参数,第一个参数为该方法所在的类的对象,第二个参数为可变参数,接受该方法所需要的所有参数。
//1.获取类对象Objectobject=clazz.newInstance(); //2.根据方法名称和参数类型获取指定的方法Methodmethod=clazz.getDeclaredMethod("sayHello", String.class); //3.调用该方法method.invoke(object,"hello");