java提供了一个反射库,通过其可以在运行中分析类的能力,即获取类对应的信息(定义的属性、方法等)
测试类
public class ReflectTestClass {
public int num0;
private int num1;
private static int num2;
private int sum;
public ReflectTestClass() {
}
public ReflectTestClass(int num0,int num1) {
this.num0 = num0;
this.num1 = num1;
}
public void setNum0(int num0) {
this.num0 = num0;
}
public int getNum0() {
return num0;
}
public void setNum1(int num1) {
this.num1 = num1;
}
public int getNum1() {
return num1;
}
private void addition() {
sum = num1+num0;
}
public int getSum() {
return sum;
}
}
1. Class类
要学习如何运用反射,首先要了解Class。在Java为程序运行时的所有对象维护了一个类型标识,这个信息跟随着对象所属的类。同时这些信息存储在Class类中。
获取Class对象有三种方法:
1. Object中的getClass()方法会返回Class的实例
Class class1 = testClass.getClass();
2. 任意类型使用 .class
Class class2 = ReflectTestClass.class;
3. Class的静态方法forName(String className)
Class class3 = Class.forName("com.jsk.reflect_test.ReflectTestClass");
注意:这里的名称应该包含报名及类名
注意:一个Class对象仅仅是表示一个类型,而不一定不是一个类,如:
Class class4 = int.class;
Class对象可以通过getName()获取对应类型的名称
String className = class1.getName();
System.out.println(className);
sysout:
com.jsk.reflect_test.ReflectTestClass
Class对象可以通过newInstance()获取对应类型的实例,前提是存在默认的构造方法,否则会抛出异常
ReflectTestClass testClass2 = (ReflectTestClass) class3.newInstance();
2. 常用的类
在利用反射的时候通常还会用到一下几个类:
Field、Method、Constructor、Modifier
2.1 Field
Class的对象可以通过调用方法获取getFields()或getDeclaredFields()方法获取类的属性,不同的是getFields()获取的是public修饰的,而或getDeclaredFields获取的是所有声明的属性。
Field[] fields = class3.getFields();
Field[] fields2 = class3.getDeclaredFields();
通过Field可以获取对应属性的名称、类型以及修饰符
for (int i = 0; i < fields2.length; i++) {
Field field = fields2[i];
Class type = field.getType();
String typeName = type.getName();
String name = field.getName();
int modifierInt = field.getModifiers();
boolean isPublic = Modifier.isPublic(modifierInt);
String modifierStr = Modifier.toString(modifierInt);
System.out.println("Field name:"+name+" type:"+typeName+" modifier:"+modifierStr);
}
Field name:num0 type:int modifier:public
Field name:num1 type:int modifier:private
Field name:num2 type:int modifier:private static
Field name:sum type:int modifier:private
getType() 返回属性对应的Class类型;
getName() 返回属性对应的名称;
getModifiers() 返回有个int型数据,可以Modifier的静态方法判断所声明的前缀
2.2 Constructor
对于一个Class对象,可以通过getConstructors()或getDeclaredConstructors()者获取类对应的构造方法,然后通过Constructor对象获取相应构造方法的信息
Constructor[] constructors = class3.getConstructors();
for (Constructor constructor : constructors) {
String name = constructor.getName();
int modifierInt = constructor.getModifiers();
String modifierStr = Modifier.toString(modifierInt);
Class[] paraClass = constructor.getParameterTypes();
StringBuilder builder = new StringBuilder();
for (Class paraClas: paraClass) {
String pareName = paraClas.getName();
builder.append(" "+pareName);
}
System.out.println("Method Name:"+name+" Modifiers:"+modifierStr+" ParameterTypes:"+builder.toString());
}
Method Name:com.jsk.reflect_test.ReflectTestClass Modifiers:public ParameterTypes:
Method Name:com.jsk.reflect_test.ReflectTestClass Modifiers:public ParameterTypes: int int
getName() 获取方法的名称
getModifiers() 获取方法声明的前缀
getParameterTypes() 获取参数的类型
2.3 Method
对于一个Class对象,可以通过getMethods()或getDeclaredMethods()者获取类对应声明的方法,然后通过Method对象获取相应构造方法的信息
Method[] methods = class3.getMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
String name = method.getName();
int modifierInt = method.getModifiers();
String modifierStr = Modifier.toString(modifierInt);
Class returnType = method.getReturnType();
String returnStr = returnType.getName();
Class[] paraClass = method.getParameterTypes();
StringBuilder builder = new StringBuilder();
for (Class paraClas: paraClass) {
String pareName = paraClas.getName();
builder.append(pareName);
}
System.out.println("Method Name:"+name+" Modifiers:"+modifierStr+" ReturnType:"+returnStr+" ParameterTypes:"+builder.toString());
}
Method Name:getSum Modifiers:public ReturnType:int ParameterTypes:
Method Name:getNum0 Modifiers:public ReturnType:int ParameterTypes:
Method Name:getNum1 Modifiers:public ReturnType:int ParameterTypes:
Method Name:setNum0 Modifiers:public ReturnType:void ParameterTypes:int
Method Name:setNum1 Modifiers:public ReturnType:void ParameterTypes:int
Method Name:wait Modifiers:public final ReturnType:void ParameterTypes:
Method Name:wait Modifiers:public final ReturnType:void ParameterTypes:long int
Method Name:wait Modifiers:public final native ReturnType:void ParameterTypes:long
Method Name:equals Modifiers:public ReturnType:boolean ParameterTypes:java.lang.Object
Method Name:toString Modifiers:public ReturnType:java.lang.String ParameterTypes:
Method Name:hashCode Modifiers:public native ReturnType:int ParameterTypes:
Method Name:getClass Modifiers:public final native ReturnType:java.lang.Class ParameterTypes:
Method Name:notify Modifiers:public final native ReturnType:void ParameterTypes:
Method Name:notifyAll Modifiers:public final native ReturnType:void ParameterTypes:
getType() 返回属性对应的Class类型;
getName() 返回属性对应的名称;
getModifiers() 返回有个int型数据,可以Modifier的静态方法判断所声明的前缀
getReturnType() 获取返回值的类型
2.4 Modifier
对于Field、Method、Constructor通过方法getModifiers()获取的修饰语,返回的是一个int值,要获取其具体的信息可以通过Modifier的相关静态方法获取
static int classModifiers()
static int constructorModifiers()
static int fieldModifiers()
static int interfaceModifiers()
static boolean isAbstract(int mod)
static boolean isFinal(int mod)
static boolean isInterface(int mod)
static boolean isNative(int mod)
static boolean isPrivate(int mod)
static boolean isProtected(int mod)
static boolean isPublic(int mod)
static boolean isStatic(int mod)
static boolean isStrict(int mod)
static boolean isSynchronized(int mod)
static boolean isTransient(int mod)
static boolean isVolatile(int mod)
static int methodModifiers()
static String toString(int mod)
3. 属性操作
对于一个类的属性,同样可以利用反射机制对其操作
ReflectTestClass testClass = new ReflectTestClass();
Class cls = testClass.getClass();
Field field = cls.getDeclaredField("num1");
field.setAccessible(true);
field.set(testClass, 123);
int i = (int) field.get(testClass);
System.out.println(i);
在以上,ReflectTestClass类中声明有num1属性。首先获取其的Class对象,然后可以通过
getField(String name)
或getDeclaredField(String name)方法获取相应的属性.
然后可以用get和set对对应对象的属性进行取值和赋值,
注意:如果该属性是私有的,不可操作这样会抛出异常IllegalAccessException,可以调用setAccessible(boolean flag)进行设置
4. 方法操作
对于Method对象,可以调用
invoke(Object obj, Object… args)方法进行调用其包装的方法。
Class cls = Class.forName("com.jsk.reflect_test.ReflectTestClass");
ReflectTestClass testClass = (ReflectTestClass) cls.newInstance();
Method method = cls.getDeclaredMethod("addition", int.class);
method.setAccessible(true);
int num = (int) method.invoke(testClass, 1234);
System.out.println(num);
首先也应注意方法是否能对为外部开放,同时可以通过setAccessible设置
invoke方法,如果调用的是静态方法,obj可以为null,其余需类对应的对象
invoke会返回返回类型的包装类型,如int会返回Integer