在我们做项目时有时为了优化开发效率通常会使用一些第三方框架,这些框架有网络请求、图片处理、json解析、注解框架等等,尤其在我们想简化代码提高开发效率时就会想到使用第三方的注解框架,比较流行的有butterknife、annotations、xutils等,在我们使用这些框架为我们带来便利的同时,总是想了解一下它们的运行原理和机制,拿butterknife来说,想要写出这样一套框架出来必定要用到一些Java知识,其中就包括注解原理、Java的反射机制。
这篇文章先初步了解一下Java的反射机制:
1. 反射机制是什么
反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
2. 反射机制能做什么
反射机制主要提供了以下功能:
3.反射机制的相关API
java.lang.Class;
java.lang.reflect.Constructor; java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
以下将通过具体代码实现来说明反射机制可以做哪些事情
ReflectClass 代码
package com.yd.test.javareflect;
import java.io.Serializable;
public class ReflectClass extends BaseReflectClass implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private int intValue = 0;
private String stringValue = null;
public void method01(){
System.out.println("ReflectClass_01");
}
public void method02(){
System.out.println("ReflectClass_02");
}
public void method03(int intValue, String stringValue){
System.out.println("ReflectClass_Method03"+" intValue: "+intValue+" stringValue: "+ stringValue);
}
public void method04(){
System.out.println("intValue: "+intValue+"stringValue: "+stringValue);
}
}
BaseReflectClass 代码
package com.yd.test.javareflect;
public class BaseReflectClass {
int BaseClassMod = 3;
public void baseMethod(){
}
}
public static void main(String[] args) {
/** 获取类的完整包名 */
ReflectClass reflectClass = new ReflectClass();
System.out.println(reflectClass.getClass().getName());
}
输出:
com.yd.test.javareflect.ReflectClass
Class..getClass().getName()方法可获取类的完整包名
/** 三种实例化Class的方法 */
Class class1 = null;
Class class2 = null;
Class class3 = null;
try {
class1 = Class.forName("com.yd.test.javareflect.ReflectClass");
// java语言中任何一个java对象都有getClass 方法
class2 = new ReflectClass().getClass();
//java中每个类型都有class 属性
class3 = ReflectClass.class;
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
以上三种实例化对象(类)的方式,一般我们用的比较多的也就是Class.forName(“xxx”)这种方式了,如果懒得去看包名,也可以用其它的方式。
/** 获取对象实现的接口和继承的类 */
System.out.println(
class1.getSuperclass().getName()+" / "
+class2.getSuperclass().getName()+" / "
+class3.getSuperclass().getName()
);
Class classes[] = class1.getInterfaces();
for (int i = 0; i < classes.length; i++) {
System.out.println(classes[i].getName());
}
输出:
com.yd.test.javareflect.BaseReflectClass / com.yd.test.javareflect.BaseReflectClass / com.yd.test.javareflect.BaseReflectClass
java.io.Serializable
Class.getSuperclass().getName()可以获取继承了哪些类和实现的接口。
User类代码
package com.yd.test.javareflect;
public class User {
private int age;
private String name;
public User(){}
public User(String name) {
super();
this.name = name;
}
public User(int age, String name) {
super();
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return getName()+"/"+getAge();
}
}
/* 实例化对象并给对象中的属性赋值 */
Class c = null;
try {
c = Class.forName("com.yd.test.javareflect.User");
// 实例化User对象
User user = (User) c.newInstance();
user.setAge(25);
user.setName("danity");
System.out.println(user.toString());
输出:
danity/25
Constructor> constructor[] = c.getConstructors();
// 获取每个构造函数所需要的参数类型信息
for (int i = 0; i < constructor.length; i++) {
// getParameterTypes():获取构造函数参数类型
Class arrayClass[] = constructor[i].getParameterTypes();
System.out.print("cons[" + i + "] (");
for (int j = 0; j < arrayClass.length; j++) {
if (j == arrayClass.length - 1)
System.out.print(arrayClass[j].getName());
else
System.out.print(arrayClass[j].getName() + ", ");
}
System.out.println(")");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
输出:
cons[0] (java.lang.String)
cons[1] (int, java.lang.String)
cons[2] ()
以上可以看出,利用反射可以获取类构造函数的参数类型信息、对一个对象的属性进行赋值,这也是比较常用的方法。
/* 获取类的所有属性 */
try {
Class rClass = Class.forName("com.yd.test.javareflect.ReflectClass");
// Field: 获取属性,下面还会讲到获取类的方法,注意区分
Field field[] = rClass.getDeclaredFields();
for (int i = 0; i < field.length; i++) {
System.out.println(field[i].getName());
// 获取修饰权限符
int mo = field[i].getModifiers();
System.out.println("mo: "+mo);
String priv = Modifier.toString(mo);
// 属性类型
Class type = field[i].getType();
System.out.println(priv + " " + type.getName() + " " + field[i].getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
输出:
serialVersionUID
mo: 26
private static final long serialVersionUID
intValue
mo: 2
private int intValue
stringValue
mo: 2
private java.lang.String stringValue
/* 获取父类和实现的接口的所有属性 */
Class rClass = null;
try {
rClass = Class.forName("com.yd.test.javareflect.ReflectClass");
Field field[] = rClass.getFields();
for (int j = 0; j < field.length; j++) {
System.out.println(field[j].getName());
// 获取修饰权限符
int mo = field[j].getModifiers();
System.out.println("mo: "+mo);
String priv = Modifier.toString(mo);
// 属性类型
Class type = field[j].getType();
System.out.println(priv + " " + type.getName() + " " + field[j].getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
package com.yd.test.javareflect;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Main2 {
/**
* @param args
*/
public static void main(String[] args) {
try {
Class fClass = Class.forName("com.yd.test.javareflect.ReflectClass");
// Method[]: 方法数组
Method method[] = fClass.getMethods();
for (int i = 0; i < method.length; i++) {
// returnType :返回类型
Class returnType = method[i].getReturnType();
System.out.println("ReturnType: "+returnType);
// 获取参数类型
Class para[] = method[i].getParameterTypes();
int temp = method[i].getModifiers();
System.out.print("Modifier.toString: "+Modifier.toString(temp) + " ");
System.out.print(returnType.getName() + " ");
System.out.print(method[i].getName() + " ");
System.out.print("(");
for (int j = 0; j < para.length; ++j) {
System.out.print(para[j].getName() + " " + "arg" + j);
if (j < para.length - 1) {
System.out.print(",");
}
}
// 获取异常类型
Class> exce[] = method[i].getExceptionTypes();
if (exce.length > 0) {
System.out.print(") throws ");
for (int k = 0; k < exce.length; ++k) {
System.out.print(exce[k].getName() + " ");
if (k < exce.length - 1) {
System.out.print(",");
}
}
} else {
System.out.print(")");
}
System.out.println();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
输出:
ReturnType: void
Modifier.toString: public void method01 ()
ReturnType: void
Modifier.toString: public void method02 ()
ReturnType: void
Modifier.toString: public void method03 (int arg0,java.lang.String arg1)
ReturnType: void
Modifier.toString: public void method04 ()
ReturnType: void
Modifier.toString: public void baseMethod ()
ReturnType: void
Modifier.toString: public final void wait () throws java.lang.InterruptedException
ReturnType: void
Modifier.toString: public final void wait (long arg0,int arg1) throws java.lang.InterruptedException
ReturnType: void
Modifier.toString: public final native void wait (long arg0) throws java.lang.InterruptedException
ReturnType: int
Modifier.toString: public native int hashCode ()
ReturnType: class java.lang.Class
Modifier.toString: public final native java.lang.Class getClass ()
ReturnType: boolean
Modifier.toString: public boolean equals (java.lang.Object arg0)
ReturnType: class java.lang.String
Modifier.toString: public java.lang.String toString ()
ReturnType: void
Modifier.toString: public final native void notify ()
ReturnType: void
Modifier.toString: public final native void notifyAll ()
信息比较多,捡需要的信息看
下面是Java反射比较重要的用法:
ReflectClass 代码
package com.yd.test.javareflect;
import java.io.Serializable;
public class ReflectClass extends BaseReflectClass implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private int intValue = 0;
private String stringValue = null;
public void method01(){
System.out.println("ReflectClass_01");
}
public void method02(){
System.out.println("ReflectClass_02");
}
public void method03(int intValue, String stringValue){
System.out.println("ReflectClass_Method03"+" intValue: "+intValue+" stringValue: "+ stringValue);
}
public void method04(){
System.out.println("intValue: "+intValue+"stringValue: "+stringValue);
}
}
public static void main(String[] args) {
/**
* 通过反射给对象类中的某个方法赋值传值
*/
try {
Class> fclass = Class.forName("com.yd.test.javareflect.ReflectClass");
// 调用ReflectClass的“method01方法”
Method method = fclass.getMethod("method01");
method.invoke(fclass.newInstance());
// int.class, string.class 对应方法的参数类型,位置不能写错
Method mod = fclass.getMethod("method03", int.class, String.class);
mod.invoke(fclass.newInstance(),20,"test");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
输出:
ReflectClass_01
ReflectClass_Method03 intValue: 20 stringValue: test
从输出内容来看,通过反射调用了类中的两个方法并对方法参数进行了操作
public static void main(String[] args) {
try {
Class sClass = Class.forName("com.yd.test.javareflect.ReflectClass");
//实例化这个类赋给obj
Object obj = sClass.newInstance();
Field field = sClass.getDeclaredField("intValue");
//打破封装
//使用反射机制可以打破封装性,导致了java对象的属性不安全。
field.setAccessible(true);
//给obj对象的intValue属性赋值"3"
field.set(obj, 3);
// 打印值
System.out.println(field.get(obj));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
输出:
3
以上是Java反射的基本用法,还有一些动态代理的用法有兴趣的可以自己找找资料。
现在,离掌握注解知识又更近了一步……