最近本着不求甚解的态度重温了一下主流框架的源码,所以趁热打铁的总结一下,学习框架或开发框架所必备的基础知识:
1.1、简介
本文简单总结一下Java反射和注解,反射可以算是必备条件了,基本学习的主流框架中都会看到反射的身影,他的灵活使用也为很多逻辑的扩展提供了可能,通过Java的反射机制,可以在程序中访问已经加载到JVM中的Java对象的描述,实现访问、检测、修复和修改描述Java本身对象的功能,Java中的java.lang.reflect包提供使用注解功能。
Java中的所有类均即成了Object类,在Object类中定义了getClass方法,该方法返回一个Class的对象:
Class c = object.getClass();
利用返回的Class,即可访问Class描述信息,如:属性、方法‘构造函数等;
1.2、访问构造函数
Modifier常用的解析方法
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 extends ConstructorExample> 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、访问成员变量
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 、访问方法
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、注解的标记
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 extends ConstructorExample> 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("-------------");
}
}
}
反射和注解的介绍,以及二者的使用介绍完毕,在平时的使用过程中也基本就是这样使用的,只不过功能逻辑的实现复杂程度不同,后面会有一篇关于注解自动生成代码的文章,也是框架中注解的常用实例。