反射机制可以帮助我们在动态运行时,获得任意一个类的所有的构造器、方法、变量。很多主流框架都使用了反射技术.像SSH框架就采用了xml做配置文件+反射技术。
为了更好说明反射技术,我们将利用TestObject类来演示:
import java.util.HashMap;
public class TestObject {
private String myName;
private int myArg;
public String hobby;
public String schoolName;
protected String age;
public String[] arr = new String[]{"hello","world"};
public TestObject(){
System.out.println("调用TestObject的无参构造方法");
this.myName = "wongkyunban";
this.myArg = 23;
}
public TestObject(String name){
System.out.printf("调用TestObject的有一个String型参数的构造方法:%s\n",name);
this.myName = name;
this.myArg = 21;
}
private TestObject(int arg){
System.out.printf("调用TestObject的有一个int型参数的构造方法:%d\n",arg);
this.myName = "Jack";
this.myArg = arg;
}
public TestObject(int arg,String name){
System.out.printf("调用TestObject的有两个参数的构造方法");
this.myName = name;
this.myArg = arg;
}
public String getMyName() {
return myName;
}
public void setMyName(String myName) {
this.myName = myName;
}
public int getMyArg() {
return myArg;
}
public void setMyArg(int myArg) {
this.myArg = myArg;
}
private void con(){
System.out.printf("hello,%s\n","您调用了一个私有方法");
}
public void printHobby(){
System.out.printf("Hobby:%s\n",hobby);
}
protected void byebye(){
System.out.printf("Bye bye!\n");
}
public void handleData(String arg1 ,HashMap<Integer,String> map){
System.out.printf("%s--->%s\n",arg1,map.get("name"));
}
private void say(String name){
System.out.printf("hello,%s\n",name);
}
}
使用反射技术获得所有构造方法(包括私有的,非私有的)
默认权限的指的是没有修饰符修饰的。
方法 | 描述 |
public Constructor getConstructor(Class… parameterTypes) | 获得指定的具有public访问权限的构造方法 |
public Constructor[] getConstructors() | 获得所有的具有public访问权限的构造方法 |
public Constructor getDeclaredConstructor(Class… parameterTypes) | 获得指定的构造方法,不管它的访问权限是什么。 |
public Constructor[] getDeclaredConstructors() | 获得所有的构造方法,包括public, private,protected和默认权限的 |
。
示例代码:
//获取构造函数
private void getConstructor(){
try {
Class<?> clazz = Class.forName("TestObject");
//获得所有的具有public访问权限的构造方法
Constructor<?>[] constructors = clazz.getConstructors();
System.out.printf("所有的具有public访问权限的构造方法:\n");
for(Constructor o:constructors){
System.out.printf("%s\n",o.toString());
}
//获得指定的具有public访问权限的构造方法
Constructor<?> constructor = clazz.getConstructor(String.class);
System.out.printf("获得指定的具有public访问权限的构造方法:\n");
System.out.printf("%s\n",constructor.toString());
//获得所有的构造方法,包括public, private,protected和默认权限的
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
System.out.printf("获得所有的构造方法,包括public, private,protected和默认权限的:\n");
for(Object o:declaredConstructors){
System.out.printf("%s\n",o.toString());
}
//获得指定的构造方法,不管它的访问权限是什么
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(int.class);
System.out.printf("获得指定的构造方法,不管它的访问权限是什么:\n");
System.out.printf("%s\n",declaredConstructor.toString());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
使用获得的构造方法(包括私有的,非私有的)实例化对象。
注意事项: 如果该方法,或者该变量不是 public 访问权限的,我们应该调用相应的 setAccessible(true) 方法,才能访问得到。
//使用获得的构造函数,构造对象
public void useConstructor(){
try {
Class<?> clazz = Class.forName("TestObject");
Constructor constructor = clazz.getConstructor(String.class);
Object o = constructor.newInstance("Hello");
TestObject testObject = (TestObject) o;
testObject.byebye();
Constructor privateConstructor = clazz.getDeclaredConstructor(int.class);
//privateConstructor的访问权限不是public所以一定要执行下面这条语句
privateConstructor.setAccessible(true);
Object o1 = privateConstructor.newInstance(88);
TestObject testObject1 = (TestObject)o1;
testObject1.byebye();
}catch (Exception e){
e.printStackTrace();
}
}
使用反射获得所有的 Filed 变量
方法 | 描述 |
public Field[] getFields() | 获得所有的具有public访问权限的字段 |
public Field getField(String name) | 获得指定的具有public访问权限的字段 |
public Field[] getDeclaredFields() | 获得所有字段,包括public, private,protected和默认权限的字段 |
public Field getDeclaredField(String name) | 获得指定的字段,字段的访问权限包括public, private,protected和默认权限的 |
示例代码:
//获取所有字段
public void getMyField(){
try {
Class<?> clazz = Class.forName("TestObject");
//获得所有的具有public访问权限的字段
Field[] fields = clazz.getFields();
System.out.printf("获得所有的具有public访问权限的字段:\n");
for(Field o:fields){
System.out.printf("%s\n",o.toString());
}
//获得指定的具有public访问权限的字段
System.out.printf("获得指定的具有public访问权限的字段:\n");
Field field = clazz.getField("hobby");
System.out.printf("%s\n",field.toString());
//获得所有字段,包括public, private,protected和默认权限的字段
Field[] declaredfields = clazz.getDeclaredFields();
System.out.printf("获得所有的字段,包括public, private,protected和默认权限的字段:\n");
for(Field o:declaredfields){
System.out.printf("%s\n",o.toString());
}
//获得指定的字段,字段的访问权限包括public, private,protected和默认权限的
System.out.printf("获得指定的字段,字段的访问权限包括public, private,protected和默认权限的:\n");
Field declaredField = clazz.getDeclaredField("myName");
System.out.printf("%s\n",declaredField.toString());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
使用获得的字段
注意:如果该方法,或者该变量不是 public 访问权限的,我们应该调用相应的 setAccessible(true) 方法,才能访问得到
//使用获得的字段
public void useMyfield(){
try {
Class<?> clazz = Class.forName("TestObject");
Field field = clazz.getField("hobby");//有public权限的
TestObject object = new TestObject();
System.out.printf("%s\n",(String)field.get(object));
field.set(object,"PingPong");
System.out.printf("%s\n",(String)field.get(object));
Field privateField = clazz.getDeclaredField("myName");
privateField.setAccessible(true);//对于访问权限不是public的字段,要想访问,必须调用setAccessible。
System.out.printf("%s\n",(String)privateField.get(object));
privateField.set(object,"Wong");
System.out.printf("%s\n",(String)privateField.get(object));
}catch (Exception e){
e.printStackTrace();
}
}
使用反射获取所有的 Method
方法 | 描述 |
public Method[] getMethods() | 获得所有的具有public访问权限的方法 |
public Method getMethod(String name, Class<?>… parameterTypes) | 获得指定的具有public访问权限的方法 |
public Method[] getDeclaredMethods() | 获得所有方法,包括public, private,protected和默认权限的方法 |
public Method getDeclaredMethod(String name, Class<?>… parameterTypes) | 获得指定的方法,方法的访问权限包括public, private,protected和默认权限的 |
示例代码:
//获取所有方法
public void getAllMethod(){
try {
Class<?> clazz = Class.forName("TestObject");
//获得所有的具有public访问权限的方法
Method[] methods = clazz.getMethods();
System.out.printf("获得所有的具有public访问权限的方法:\n ");
for(Object o:methods){
System.out.printf("%s\n",o.toString());
}
//获得指定的具有public访问权限的方法
Method method = clazz.getMethod("setMyArg", int.class);
System.out.printf("获得指定的具有public访问权限的方法:\n ");
System.out.printf("%s\n",method.toString());
//获得所有方法,包括public, private,protected和默认权限的方法
Method[] declaredMethods = clazz.getDeclaredMethods();
System.out.printf("获得所有方法,包括public, private,protected和默认权限的方法:\n");
for(Object o:declaredMethods){
System.out.printf("%s\n",o.toString());
}
//获得指定的方法,方法的访问权限包括public, private,protected和默认权限的
Method declaredMethod = clazz.getDeclaredMethod("say", String.class);
System.out.printf("获得指定的方法,方法的访问权限包括public, private,protected和默认权限的:\n");
System.out.printf("%s\n",declaredMethod.toString());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
使用已获得的方法
注意事项: 如果该方法,或者该变量不是 public 访问权限的,我们应该调用相应的 setAccessible(true) 方法,才能访问得到。如果不用就会报如下错:
java.lang.IllegalAccessException: Class Main can not access a member of class TestObject with modifiers "private"
//使用已获得的方法
public void useMethod(){
try {
Class<?> clazz = Class.forName("TestObject");
Method method = clazz.getMethod("handleData", String.class, HashMap.class);//有public权限的
TestObject testObject = new TestObject();
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("name", "Kingkong");
method.invoke(testObject, "Tom", hashMap);
Method privateMethod = clazz.getDeclaredMethod("con");
privateMethod.setAccessible(true);//对于访问权限不是public的方法,要想访问,必须调用setAccessible。
privateMethod.invoke(testObject);
}catch (Exception e){
e.printStackTrace();
}
}
使用反射操作数组
//利用反射技术处理数组
public void handlArray() {
String[] nameArr = new String[]{"Tom", "John", "Lucy", "Barkerly"};
Array.set(nameArr, 0, "Wongkyunban"); //修改数组的值
Class clazz = nameArr.getClass();
if (clazz.isArray()) {
int len = Array.getLength(nameArr);
for (int i = 0; i < len; i++) {
Object object = Array.get(nameArr, i);
String className = object.getClass().getName();
System.out.println("--> object=" + object + ",className=" + className);
}
}
}
使用反射获得泛型类型
//使用反射获得泛型类型
public void getGenericType(){
try {
//Class<?> clazz = TestObject.class;与下面等价
Class<?> clazz = Class.forName("TestObject");
Method genericTypeMethod = clazz.getDeclaredMethod("handleData", String.class,HashMap.class);
//获得所有的参数类型
Type[] genericParameterTypes = genericTypeMethod.getGenericParameterTypes();
//检验是否为空
if (null == genericParameterTypes || genericParameterTypes.length < 1) {
return;
}
//取方法第2个参数,获得泛型参数的类型
ParameterizedType parameterizedType = (ParameterizedType)genericParameterTypes[1];
Type rawType = parameterizedType.getRawType();
System.out.printf("--->raw type:%s\n",rawType);
//取得第二个泛型参数类型
Type[] actualTypeArgs = parameterizedType.getActualTypeArguments();
if(actualTypeArgs == genericParameterTypes || actualTypeArgs.length < 1){
return;
}
//打印出每一个类型
for (int i = 0; i < actualTypeArgs.length; i++){
Type type = actualTypeArgs[i];
System.out.printf("--->Type:%s\n",type);
}
}catch (Exception e){
e.printStackTrace();
}
}
获得 Metho,Field,Constructor 的访问权限 ( public,private,ptotected 等)
//获得Metho,Field,Constructor 的访问权限
public void showPermmit(){
try {
Class<?> clazz = Class.forName("TestObject");
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor:constructors){
int modifier = constructor.getModifiers();
System.out.printf("构造器%s,权限是%s\n",constructor.toString(), Modifier.toString(modifier));
}
System.out.printf("\n\n");
Field[] fields = clazz.getDeclaredFields();
for (Field field:fields){
int modifier = field.getModifiers();
System.out.printf("字段%s,权限是%s\n",field.toString(), Modifier.toString(modifier));
}
System.out.printf("\n\n");
Method[] methods = clazz.getDeclaredMethods();
for (Method method:methods){
int modifier = method.getModifiers();
System.out.printf("方法%s,权限是%s\n",method.toString(), Modifier.toString(modifier));
}
}catch (Exception e){
e.printStackTrace();
}
}
演示demo