当前位置: 首页 > >

Java反射、注解

发布时间:

最*本着不求甚解的态度重温了一下主流框架的源码,所以趁热打铁的总结一下,学*框架或开发框架所必备的基础知识:


Java反射Java注解注解代码自动生成Java动态代理AOP
一、反射

1.1、简介


本文简单总结一下Java反射和注解,反射可以算是必备条件了,基本学*的主流框架中都会看到反射的身影,他的灵活使用也为很多逻辑的扩展提供了可能,通过Java的反射机制,可以在程序中访问已经加载到JVM中的Java对象的描述,实现访问、检测、修复和修改描述Java本身对象的功能,Java中的java.lang.reflect包提供使用注解功能。


Java中的所有类均即成了Object类,在Object类中定义了getClass方法,该方法返回一个Class的对象:


Class c = object.getClass();

利用返回的Class,即可访问Class描述信息,如:属性、方法‘构造函数等;


1.2、访问构造函数


Java提供了一下通过反射获取构造函数的方法:
    getConstructors():获取权限位Public的构造函数getConstructors(Class … parameterTypes):获取权限为public且指定参数类型的构造函数getDeclaredConstructors():按照声明顺序返回所有构造函数,包private类型getDeclaredConstructors(Class … parameterTypes):获取指定参数类型的构造函数

针对Constructor常用的方法:
    isVarArgs():是否允许可变数量参数,返回boolean ,true表示有,false表示没有getParameterTypes():按照声明的顺序返回参数类型getExceptionTypes():返回抛出异常的类型newInstance():根据传入的参数调用构造函数创建实例setAccessible():默认不允许反射privite修饰的方法和属性,但如果先执行并设置为true,则可以反射getModifiers():获得可以解析出方法修饰符的整数

Modifier常用的解析方法


    isPublic(int mode):是否为Public修饰符isProtected(int mode):是否为Protected修饰符isPrivate(int mode):是否为Private修饰符isStatic(int mode):是否为Static修饰符isFinal(int mode):是否为Final修饰符toString(int mode):以字符串返回修饰符

实例:
    创建实例ConstructExample

public class ConstructorExample {

int number;
public String name;
protected float aFloat;
private ConstructorExample() {
}

protected ConstructorExample(int number) {
this.number = number;
}

public ConstructorExample(String name, int number) throws NumberFormatException {
this.number = number;
this.name = name;
}

public void prinln() {
System.out.println("name = " + name);
System.out.println("number = " + number);
}
}

? ?2、反射获取构造函数信息


public static void main(String[] args) {
ConstructorExample constructorExample = new ConstructorExample(10);
Class classExample = constructorExample.getClass();
Constructor[] constructors = classExample.getDeclaredConstructors(); // 获取所有构造函数
for (int i = 0; i < constructors.length; i++) {
Constructor constructor = constructors[i]; //获取构造函数
System.out.println("是否有可变参数");
System.out.println(constructor.isVarArgs());
System.out.println("构造函数的参数类型");
Class[] classes = constructor.getParameterTypes(); // 获取参数类型
System.out.println("构造函数的修饰类型");
int modifier = constructor.getModifiers();
if (modifier == Modifier.PRIVATE){ // 判断修饰符类型
System.out.println("Private");
}else if (modifier == Modifier.PROTECTED){
System.out.println("Protected");
}else if (modifier == Modifier.PUBLIC){
System.out.println("Public");
}
for (Class c : classes) {
System.out.println(c);
}
System.out.println("可能抛出的异常类型");
Class[] classException = constructor.getExceptionTypes(); // 获取抛出异常类型
for (Class c : classException) {
System.out.println(c);
}
ConstructorExample example = null;
while (example == null) {
try {
if (i == 2) {
example = (ConstructorExample) constructor.newInstance();// 创建实例
} else if (i == 1) {
example = (ConstructorExample) constructor.newInstance(20);
} else {
example = (ConstructorExample) constructor.newInstance("ABC", 50);
}
} catch (Exception e) {
System.out.println("私有构造函数抛出异常,设置Accessible为true");
constructor.setAccessible(true); // 处理私有构造函数
}
}
if (example != null) {
example.prinln(); // 调用方法
System.out.println();
}
}

3、运行代码输出信息(依次为三个构造函数信息)



1.3、访问成员变量


Java提供反射获取变量方法
    getFields():获取所有权限为Public的属性getFields(String name):获取名称为name,修饰符Public的属性getDeclaredFields():按声明顺序返回所有属性getDeclaredFields(String name):获取指定成员变量

Fields的常用方法
    getName():获取成员变量的名称getType():获取成员变量的Class对象get(Object o):获取指定对象Object的Field变量set(Object,Value):指定Object对象的Field属性设置值为valuegetInt()/setInt():获取和设置Object中类型为Int的属性值getFloat()/setFloat():获取和设置Object中类型为Float的属性值getBoolean()/setBoolean():获取和设置Object中类型为Boolean的属性值setAccessible():默认不允许反射privite修饰的方法和属性,但如果先执行并设置为true,则可以反射getModifiers():获得可以解析出方法修饰符的整数

实例
    在上面的类中添加成员变量(Private 处理和构造函数一致,这里不做处理)

int number;
public String name;
protected float aFloat;

? ? 2、反射获取成员变量信息


Field[] fields = classExample.getDeclaredFields();
for (Field f: fields) {
System.out.println("属性名称 = "+f.getName());
System.out.println("属性类型 = "+f.getType());
try {
System.out.println("属性默认值 = "+f.get(constructorExample));
if (f.getType().equals(int.class)){
f.set(constructorExample,5);
System.out.println("属性值修改 = "+ f.get(constructorExample));
}else if (f.getType().equals(String.class)) {
f.set(constructorExample,"ABC");
System.out.println("属性值修改 = "+f.get(constructorExample));
}else {
f.set(constructorExample,99.99f);
System.out.println("属性值修改 = "+f.get(constructorExample));
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("-------------");
}

? ?3、实例输出信息



1.4 、访问方法


Java提供反射获取方法属性的方法:
    getMethod():获取所有为Public的方法getMethod(String name,Class … parameterTypes):获取指定方法名和参数类型的public函数getDeclaredMethod():获取所有方法getDeclaredMethod(String name,Class … parameterTypes):获取指定方法名和参数类型的函数

Method的常用方法
    getName():获取方法名getParameterType():按声明顺序返回参数类型getReturnType():获取方法的返回数据类型getExceptionTypes():返回抛出异常的类型invoke(Object o,Object…argbs):利用参数argbs执行对象Object中的该方法isVarArgs():是否允许可变数量参数,返回boolean ,true表示有,false表示没有getModifiers():获得可以解析出方法修饰符的整数

实例
    在上面类中添加几个简单方法

public void prinln() {
System.out.println("name = " + name);
System.out.println("number = " + number);
}

public int action(int i,int j){
System.out.println("执行了action");
System.out.println(i+j);
return i+j;
}

protected void function() throws NullPointerException{
System.out.println("执行了function");
}

? ? 2、反射获取并调用方法


Method[] methods = classExample.getDeclaredMethods();
System.out.println("-------------");
for (Method method : methods){
System.out.println("方法名:"+method.getName());
System.out.println("返回值类型:"+method.getReturnType());
System.out.println("方法抛出的异常类型为");
Class[] classException = method.getExceptionTypes();
for (Class c : classException) {
System.out.println(c);
}
Class[] classes = method.getParameterTypes();
System.out.println("方法的参数类型为");
for (Class c:classes
) {
System.out.println(c);
}
try {
if (classes.length != 0) {
method.invoke(constructorExample, 3, 7); // 执行方法
}else {
method.invoke(constructorExample); // 执行方法
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
System.out.println("-------------");
}

? ?3、输出信息



以上就是反射获取类的构造方法、属性和方法的过程,有了这三步就可以访问类中的所有信息,极大地提高了代码的灵活性;下面来介绍下注解,基本反射和注解是一个很好的搭档,加入我们要为某种行为创造框架,那么就可以在需要使用的地方,添加注解标记,然后用反射找到指定的类或方法属性,执行相应的过程,仔细想想框架是不是就是这样出来的呢?


二、注解

2.1、注解形式


public @interface Action { // 无属性值
}

public @interface Action { // 有属性值
String action() default "A";
int value() default 0;
}

2.2、注解的标记


@target:设置使用的元素种类,如果未设置就表示用于所有元素,使用ElementType设置ElementType 枚举常量有:
    ANNOTATION_TYPE:表示用于Annotation的类型TYPE:作用与类、接口、枚举CONSTRUCTOR:作用于构造方法FIELD:作用于属性METHOD:作用于方法PARAMETER:作用于参数LOCAL_VARIABLE:表示局部变量PACKAGE:表示用于包

@Retention:设置注解的有效范围
    SOURCE:不编译到Annotation类的文件中CLASS:编译到Annotation的文件中,运行时不加在到JVM中RUNTING:运行时加载到JVM中,有效范围最大

CONSTRUCTOR、METHOD、FIELD都继承了AccessibleObject类,在AccessibleObject中定义了三个方法
    isAnnomationPresent(Class class):返回boolean,表示是否有指定的注解getAnnotation(Class class):获取指定的注解getAnnotations():获取所有的注解

2.3、实例


声明两个注解

@Target(ElementType.CONSTRUCTOR)
@Retention(RetentionPolicy.RUNTIME)
public @interface Action {
String action() default "构造函数";
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldAnnotation {
String describe() default "描述";
Class type() default void.class;
}

注解@Action 使用于构造函数,有一个描述属性,@FieldAnnotation适用于注解属性常量,包含一个String类型的描述和修饰的类型


使用注解

public class ConstructorExample {

@FieldAnnotation(describe = "名字" ,type = String.class)
public String name;
@FieldAnnotation(describe = "分数",type = int.class)
protected int core;

@Action()
public ConstructorExample(String name, int core) throws NumberFormatException {
this.core = core;
this.name = name;
}
}

反射获取

public class ReflectConstructor {

public static void main(String[] args) {
ConstructorExample constructorExample = new ConstructorExample("ABC",10);
Class classExample = constructorExample.getClass();
Constructor[] constructors = classExample.getDeclaredConstructors();
for (int i = 0; i < constructors.length; i++) {
Constructor constructor = constructors[i];
if (constructor.isAnnotationPresent(Action.class)){//是否包含Action.class注解
System.out.println("包含Action注解");
Action action = (Action) constructor.getAnnotation(Action.class);
System.out.println("注解值为 :"+action.action());
}
System.out.println("-------------");
}

Field[] fields = classExample.getDeclaredFields();
for (Field f: fields) {
System.out.println("属性名称 = "+f.getName());
System.out.println("属性类型 = "+f.getType());
try {
if (f.isAnnotationPresent(FieldAnnotation.class)) {
System.out.println("使用FieldAnnotation注解");
FieldAnnotation annotation = f.getAnnotation(FieldAnnotation.class);
System.out.println("FieldAnnotation注解参数:");
System.out.println("Describe:"+annotation.describe());
System.out.println("Type:"+annotation.type());
}

} catch (Exception e) {
e.printStackTrace();
}
System.out.println("-------------");
}
}
}

输出信息


反射和注解的介绍,以及二者的使用介绍完毕,在*时的使用过程中也基本就是这样使用的,只不过功能逻辑的实现复杂程度不同,后面会有一篇关于注解自动生成代码的文章,也是框架中注解的常用实例。



友情链接: