一、背景
最近的项目中需要使用到Java 反射的知识,以前不怎么了解,也基本没怎么用过,抽出一片时间,来具体学习和实战下Java的反射!拿来和大家分享以及记录方便以后学习!
二、反射相关概念解析
1.Class类
Class类:Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class。
如何得到各个类的字节码即Class类呢?
[1].类名.class:直接通过类.class获得。
[2].对象.getClass():通过对象调用其getClass方法获得。
[3].Class.forName("类全路径"):通过类加载器加载获得
注:Java中的原始基本类型:boolean, byte
, char
, short
, int
, long
, float
,double和关键词 void同样都有Class类,通过.class可获得它们的类字节码。
2.反射的概念
反射就是把Java类中的各种成分映射成相应的Java类,例如一个Java类中用一个Class类的对象表示一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示,例如人是一个类,那么人的大脑、双手等也是一个个类。表示Java的Class类显然要提供一系列的方法,来获得其中的变量、方法、构造方法,修饰符、包等信息,这些信息就是用相应的类的实例对象来表示,他们是Field、Method、Contructor、Package等等。
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示。
三、反射实战
测试Bean:Person.java
1 package com.hafiz.zhang.Bean;
2
3 public class Person {
4 public Integer id;
5 private String name;
6
7 public Person() {
8 }
9 public Person(Integer id, String name) {
10 super();
11 this.id = id;
12 this.name = name;
13 }
14 public Integer getId() {
15 return id;
16 }
17 public void setId(Integer id) {
18 this.id = id;
19 }
20 public String getName() {
21 return name;
22 }
23 public void setName(String name) {
24 this.name = name;
25 }
26 @Override
27 public String toString() {
28 return "Person [id=" + id + ", name=" + name + "]";
29 }
30
31 public void sayHello() throws Exception{
32 System.out.println("Hello Reflect!");
33 }
34 }
1.使用反射获取对象所属类的全路径(包括报名和类名)
1 package com.hafiz.zhang.test;
2
3 import com.hafiz.zhang.Bean.Person;
4
5 /**
6 * @author hafiz.Zhang
7 * @Date 2016年5月18日 下午4:28:35
8 * @Description 测试通过一个对象获取该对象所属于的类的全路径(包括完整包名和类名)
9 */
10 public class ReflectTest1 {
11 public static void main(String[] args) {
12 Person person = new Person();
13 System.out.println("ClassName = " + person.getClass().getName());
14 }
15 }
测试结果:
ClassName = com.hafiz.zhang.Bean.Person
2.测试使用反射实例化Class类对象
1 package com.hafiz.zhang.test;
2
3 import com.hafiz.zhang.Bean.Person;
4
5 /**
6 * @author hafiz.Zhang
7 * @Date 2016年5月18日 下午4:31:36
8 * @Description 测试获取Class类的三种方式
9 */
10 public class ReflectTest2 {
11 public static void main(String[] args) {
12 Class<?> obj1 = null;
13 Class<?> obj2 = null;
14 Class<?> obj3 = null;
15 try {
16 //一般尽量要采用这种方式进行实例化Class类对象
17 obj1 = (Class<?>) Class.forName("com.hafiz.zhang.Bean.Person");
18 } catch (ClassNotFoundException e) {
19 e.printStackTrace();
20 }
21 obj2 = new Person().getClass();
22 obj3 = Person.class;
23
24 System.out.println("ClassName:" + obj1.getName());
25 System.out.println("ClassName:" + obj2.getName());
26 System.out.println("ClassName:" + obj3.getName());
27 }
28 }
测试结果:
ClassName:com.hafiz.zhang.Bean.Person ClassName:com.hafiz.zhang.Bean.Person ClassName:com.hafiz.zhang.Bean.Person
3.测试通过Class类对象实例化其他类
1 package com.hafiz.zhang.test;
2
3 import com.hafiz.zhang.Bean.Person;
4
5 /**
6 * @author hafiz.Zhang
7 * @Date 2016年5月18日 下午4:38:15
8 * @Description 测试通过Class类对象实例化其他类
9 */
10 public class ReflectTest3 {
11 public static void main(String[] args) {
12 Class<?> clazz = null;
13 try {
14 clazz = Class.forName("com.hafiz.zhang.Bean.Person");
15 } catch (ClassNotFoundException e) {
16 e.printStackTrace();
17 }
18 Person person = null;
19 try {
20 person = (Person) clazz.newInstance();
21 } catch (InstantiationException e) {
22 e.printStackTrace();
23 } catch (IllegalAccessException e) {
24 e.printStackTrace();
25 }
26 if(null != person) {
27 person.setId(1);
28 person.setName("Hafiz.Zhang");
29 System.out.println("person=" + person);
30 }else{
31 System.out.println("实例化对象失败");
32 }
33 }
34 }
测试结果:
person=Person [id=1, name=Hafiz.Zhang]
4.测试通过Class调用其他类中的构造函数 (也可以通过这种方式通过Class创建其他类的对象)
1 package com.hafiz.zhang.test;
2
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.InvocationTargetException;
5
6 import com.hafiz.zhang.Bean.Person;
7
8 /**
9 * @author hafiz.Zhang
10 * @Date 2016年5月18日 下午4:42:08
11 * @Description 测试通过Class调用其他类中的构造函数 (也可以通过这种方式通过Class创建其他类的对象)
12 */
13 public class ReflectTest4 {
14 public static void main(String[] args) {
15 Class<?> clazz = null;
16 try {
17 clazz = Class.forName("com.hafiz.zhang.Bean.Person");
18 } catch (ClassNotFoundException e) {
19 e.printStackTrace();
20 }
21 Person p1 = null;
22 Person p2 = null;
23 Constructor<?>[] cs = clazz.getConstructors();
24 try {
25 p1 = (Person) cs[0].newInstance();//通过无参构造获得对象
26 p2 = (Person) cs[1].newInstance(1, "Hafiz.Zhang");//通过有参构造获得对象
27 } catch (InstantiationException e) {
28 e.printStackTrace();
29 } catch (IllegalAccessException e) {
30 e.printStackTrace();
31 } catch (IllegalArgumentException e) {
32 e.printStackTrace();
33 } catch (InvocationTargetException e) {
34 e.printStackTrace();
35 }
36 System.out.println("Person1=" + p1);
37 System.out.println("Person2=" + p2);
38 }
39 }
测试结果:
Person1=Person [id=null, name=null] Person2=Person [id=1, name=Hafiz.Zhang]
5.测试使用反射获取一个类实现的接口
接口Animal.java
1 package com.hafiz.zhang.Bean;
2
3 /**
4 * @author hafiz.Zhang
5 * @Date 2016年5月19日 下午6:13:37
6 * @Description 动物接口
7 */
8 public interface Animal {
9 public abstract void eat();
10 public abstract void sleep();
11 }
接口Skill.java
1 package com.hafiz.zhang.Bean;
2
3 /**
4 * @author hafiz.Zhang
5 * @Date 2016年5月19日 下午6:14:06
6 * @Description 技能接口
7 */
8 public interface Skill {
9 public abstract void sayMiao();
10 }
实现类:Cat.java
1 package com.hafiz.zhang.Bean;
2
3 public class Cat implements Animal, Skill {
4 private Integer num;
5 private String desc;
6 public Integer getNum() {
7 return num;
8 }
9
10 public void setNum(Integer num) {
11 this.num = num;
12 }
13
14 public String getDesc() {
15 return desc;
16 }
17
18 public void setDesc(String desc) {
19 this.desc = desc;
20 }
21
22 @Override
23 public void eat() {
24 System.out.println("cat eat fish");
25 }
26
27 @Override
28 public void sleep() {
29 System.out.println("cat sleep in the day");
30 }
31
32 @Override
33 public void sayMiao() {
34 System.out.println("cat say miao");
35 }
36
37 public void sayHello(String name){
38 System.out.println("Hello " + name);
39 }
40 }
测试类
1 package com.hafiz.zhang.test;
2
3 /**
4 * @author hafiz.Zhang
5 * @Date 2016年5月18日 下午4:51:29
6 * @Description 测试使用反射获取一个类实现的接口
7 */
8 public class ReflectTest5 {
9 public static void main(String[] args) {
10 Class<?> clazz = null;
11 try {
12 clazz = Class.forName("com.hafiz.zhang.Bean.Cat");
13 } catch (ClassNotFoundException e) {
14 e.printStackTrace();
15 }
16 Class<?>[] interfaces = clazz.getInterfaces();
17 System.out.println("Cat实现的接口有");
18 for(Class<?> cl : interfaces) {
19 System.out.println(cl.getName());
20 }
21 }
22 }
测试结果:
Cat实现的接口有 com.hafiz.zhang.Bean.Animal com.hafiz.zhang.Bean.Skill
6.测试通过反射取得指定类的父类
1 package com.hafiz.zhang.test;
2
3 /**
4 * @author hafiz.Zhang
5 * @Date 2016年5月18日 下午5:03:25
6 * @Description 测试通过反射取得指定类的父类
7 */
8 public class ReflectTest6 {
9 public static void main(String[] args) {
10 Class<?> clazz = null;
11 try {
12 clazz = Class.forName("com.hafiz.zhang.Bean.Cat");
13 } catch (ClassNotFoundException e) {
14 e.printStackTrace();
15 }
16 Class<?> superClass = clazz.getSuperclass();
17 System.out.println("SuperClass=" + superClass);
18 }
19 }
测试结果:SuperClass=class com.hafiz.zhang.Bean.Person
7.测试通过反射获得其他类中的全部构造函数
1 package com.hafiz.zhang.test;
2
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.Modifier;
5
6 /**
7 * @author hafiz.Zhang
8 * @Date 2016年5月18日 下午5:06:02
9 * @Description 测试通过反射获得其他类中的全部构造函数
10 */
11 public class ReflectTest7 {
12 public static void main(String[] args) {
13 Class<?> clazz = null;
14 try {
15 clazz = Class.forName("com.hafiz.zhang.Bean.Person");
16 } catch (ClassNotFoundException e) {
17 e.printStackTrace();
18 }
19 Constructor<?>[] cs = clazz.getConstructors();
20 //实现方式1
21 /*for(Constructor<?> item : cs) {
22 System.out.println("构造方法:" + item.getName());
23 }*/
24 //实现方式2
25 for(Constructor<?> item : cs) {
26 System.out.print("构造方法:");
27 System.out.print(Modifier.toString(item.getModifiers()) + " ");
28 System.out.print(item.getName() + "(");
29 Class<?>[] paramterTypes = item.getParameterTypes();
30 for(int i = 0; i < paramterTypes.length; i++) {
31 System.out.print(paramterTypes[i].getName() + " arg" + i);
32 if(i < paramterTypes.length-1) {
33 System.out.print(",");
34 }
35 }
36 System.out.println(")");
37 }
38 }
39 }
测试结果:
构造方法:public com.hafiz.zhang.Bean.Person() 构造方法:public com.hafiz.zhang.Bean.Person(java.lang.Integer arg0,java.lang.String arg1)
8. 测试通过反射获取类中的所有方法(包括方法包含的异常)
1 package com.hafiz.zhang.test;
2
3 import java.lang.reflect.Method;
4 import java.lang.reflect.Modifier;
5
6 /**
7 * @author hafiz.Zhang
8 * @Date 2016年5月18日 下午5:22:51
9 * @Description 测试通过反射获取类中的所有方法
10 */
11 public class ReflectTest8 {
12 public static void main(String[] args) {
13 Class<?> clazz = null;
14 try {
15 clazz = Class.forName("com.hafiz.zhang.Bean.Person");
16 } catch (ClassNotFoundException e) {
17 e.printStackTrace();
18 }
19 Method[] methods = clazz.getDeclaredMethods();
20 for(Method method : methods) {
21 Class<?> returnType = method.getReturnType();
22 System.out.print(Modifier.toString(method.getModifiers()) + " ");
23 System.out.print(returnType.getName() + " " + method.getName() + "(");
24 Class<?>[] paras = method.getParameterTypes();
25 for(int i = 0 ; i < paras.length ; i++) {
26 System.out.print(paras[i].getName() + " arg" + i);
27 if(i < paras.length - 1) {
28 System.out.print(",");
29 }
30 }
31 Class<?>[] exces = method.getExceptionTypes();
32 if(exces.length > 0) {
33 System.out.print(") throws ");
34 for(int j = 0; j < exces.length; j++) {
35 System.out.print(exces[j].getName());
36 if(j < exces.length - 1) {
37 System.out.print(", ");
38 }
39 }
40 }else{
41 System.out.print(")");
42 }
43 System.out.println();
44 }
45 }
46 }
测试结果:
public java.lang.String toString() public java.lang.String getName() public void setName(java.lang.String arg0) public java.lang.Integer getId() public void sayHello() throws java.lang.Exception public void setId(java.lang.Integer arg0)
9.测试通过反射获取类中所有的属性
1 package com.hafiz.zhang.test;
2
3 import java.lang.reflect.Field;
4 import java.lang.reflect.Modifier;
5
6 /**
7 * @author hafiz.Zhang
8 * @Date 2016年5月18日 下午5:38:09
9 * @Description 测试通过反射获取类中所有的属性
10 */
11 public class ReflectTest9 {
12 public static void main(String[] args) {
13 Class<?> clazz = null;
14 try {
15 clazz = Class.forName("com.hafiz.zhang.Bean.Cat");
16 } catch (ClassNotFoundException e) {
17 e.printStackTrace();
18 }
19 Field[] fields = clazz.getDeclaredFields();
20 System.out.println("=========通过反射获取指定类中所有的属性=========");
21 for(Field field : fields) {
22 System.out.println(Modifier.toString(field.getModifiers()) + " " + field.getType().getName() + " " + field.getName());
23 }
24 System.out.println("=========通过反射获取指定类实现的接口或者父类中所有的属性=========");
25 Field[] fields2 = clazz.getSuperclass().getDeclaredFields();
26 for(Field item : fields2) {
27 System.out.println(Modifier.toString(item.getModifiers()) + " " + item.getType() + " " + item.getName());
28 }
29 }
30 }
测试结果:
=========通过反射获取指定类中所有的属性========= private java.lang.Integer num private java.lang.String desc =========通过反射获取指定类实现的接口或者父类中所有的属性========= public class java.lang.Integer id private class java.lang.String name
10.测试使用反射调用指定类的方法
1 package com.hafiz.zhang.test;
2
3 import java.lang.reflect.InvocationTargetException;
4 import java.lang.reflect.Method;
5
6 /**
7 * @author hafiz.Zhang
8 * @Date 2016年5月19日 下午3:22:33
9 * @Description 测试使用反射调用指定类的方法
10 */
11 public class ReflectTest10 {
12 public static void main(String[] args) {
13 Class<?> clazz = null;
14 try {
15 clazz = Class.forName("com.hafiz.zhang.Bean.Cat");
16 } catch (ClassNotFoundException e) {
17 e.printStackTrace();
18 }
19 try {
20 //调用Cat类中的eat无参方法
21 Method method = clazz.getMethod("eat");
22 method.invoke(clazz.newInstance());
23 //调用Cat类中的sayHello有参方法
24 Method method2 = clazz.getDeclaredMethod("sayHello", String.class);
25 method2.invoke(clazz.newInstance(), "Hafiz.Zhang");
26 } catch (NoSuchMethodException e) {
27 e.printStackTrace();
28 } catch (SecurityException e) {
29 e.printStackTrace();
30 } catch (IllegalAccessException e) {
31 e.printStackTrace();
32 } catch (IllegalArgumentException e) {
33 e.printStackTrace();
34 } catch (InvocationTargetException e) {
35 e.printStackTrace();
36 } catch (InstantiationException e) {
37 e.printStackTrace();
38 }
39 }
40 }
测试结果:
cat eat fish Hello Hafiz.Zhang
11.测试通过反射调用其他类中的setter和getter方法
1 package com.hafiz.zhang.test;
2
3 import java.lang.reflect.InvocationTargetException;
4 import java.lang.reflect.Method;
5
6 /**
7 * @author hafiz.Zhang
8 * @Date 2016年5月19日 下午3:29:34
9 * @Description 测试通过反射调用其他类中的setter和getter方法
10 */
11 public class ReflectTest11 {
12 public static void main(String[] args) {
13 Class<?> clazz = null;
14 Object obj = null;
15 try {
16 clazz = Class.forName("com.hafiz.zhang.Bean.Cat");
17 obj = clazz.newInstance();
18 } catch (ClassNotFoundException e) {
19 e.printStackTrace();
20 } catch (InstantiationException e) {
21 e.printStackTrace();
22 } catch (IllegalAccessException e) {
23 e.printStackTrace();
24 }
25 getter(obj,"Desc");
26 setter(obj,"Desc","测试调用set方法",String.class);
27 getter(obj,"Desc");
28 }
29
30 private static void getter(Object obj, String name) {
31 try {
32 Method method = obj.getClass().getMethod("get"+name);
33 System.out.println(name + ":" + method.invoke(obj));
34 } catch (NoSuchMethodException e) {
35 e.printStackTrace();
36 } catch (SecurityException e) {
37 e.printStackTrace();
38 } catch (IllegalAccessException e) {
39 e.printStackTrace();
40 } catch (IllegalArgumentException e) {
41 e.printStackTrace();
42 } catch (InvocationTargetException e) {
43 e.printStackTrace();
44 }
45 }
46
47 private static void setter(Object obj, String name, String desc, Class<?> type) {
48 try {
49 Method method = obj.getClass().getMethod("set" + name, type);
50 method.invoke(obj, desc);
51 } catch (NoSuchMethodException e) {
52 e.printStackTrace();
53 } catch (SecurityException e) {
54 e.printStackTrace();
55 } catch (IllegalAccessException e) {
56 e.printStackTrace();
57 } catch (IllegalArgumentException e) {
58 e.printStackTrace();
59 } catch (InvocationTargetException e) {
60 e.printStackTrace();
61 }
62 }
63 }
测试结果:
Desc:null Desc:测试调用set方法
12.测试通过反射操作属性
1 package com.hafiz.zhang.test;
2
3 import java.lang.reflect.Field;
4
5 /**
6 * @author hafiz.Zhang
7 * @Date 2016年5月19日 下午3:41:59
8 * @Description 测试通过反射操作属性
9 */
10 public class ReflectTest12 {
11 public static void main(String[] args) {
12 Class<?> clazz = null;
13 Object obj = null;
14 try {
15 clazz = Class.forName("com.hafiz.zhang.Bean.Cat");
16 obj = clazz.newInstance();
17 Field field = clazz.getDeclaredField("desc");
18 //若要设置private属性,需要设置
19 field.setAccessible(true);//设置成员变量可访问,包括private成员变量(暴力反射),private成员通过这步操作才能被访问
20 field.set(obj, "this is test demo");
21 System.out.println("Desc=" + field.get(obj));
22 } catch (ClassNotFoundException e) {
23 e.printStackTrace();
24 } catch (InstantiationException e) {
25 e.printStackTrace();
26 } catch (IllegalAccessException e) {
27 e.printStackTrace();
28 } catch (NoSuchFieldException e) {
29 e.printStackTrace();
30 } catch (SecurityException e) {
31 e.printStackTrace();
32 }
33
34 }
35 }
测试结果:Desc=this is test demo
13.测试通过反射进行数组操作
1 package com.hafiz.zhang.test;
2
3 import java.lang.reflect.Array;
4
5 /**
6 * @author hafiz.Zhang
7 * @Date 2016年5月19日 下午4:52:21
8 * @Description 测试通过反射进行数组操作
9 *
10 */
11 public class ReflectTest13 {
12 public static void main(String[] args) {
13 Integer[] array = {1,2,3,4,5,6};
14 Class<?> clazz = array.getClass().getComponentType();
15 System.out.println("数组类型:" + clazz.getName());
16 System.out.println("数组长度:" + Array.getLength(array));
17 System.out.println("数组第一个元素:" + Array.get(array, 0));
18 Array.set(array, 0, 8);
19 System.out.println("修改之后数组第一个元素:" + Array.get(array, 0));
20 System.out.println("=============反射修改数组长度=================");
21 Integer[] arr2 = (Integer[])changeLength(array, 10);
22 print(arr2);
23 }
24 private static void print(Object obj) {
25 Class<?> clazz = obj.getClass();
26 if(!clazz.isArray()) {
27 return;
28 }
29 System.out.println("数组长度为:" + Array.getLength(obj));
30 for(int i = 0; i < Array.getLength(obj); i++){
31 System.out.print(Array.get(obj, i) + " ");
32 }
33 }
34 public static Object changeLength(Object obj, Integer length){
35 Class<?> clazz = obj.getClass().getComponentType();
36 Object newArr = Array.newInstance(clazz, length);
37 Integer len = Array.getLength(obj);
38 System.arraycopy(obj, 0, newArr, 0, len);
39 return newArr;
40 }
41 }
测试结果:
数组类型:java.lang.Integer 数组长度:6 数组第一个元素:1 修改之后数组第一个元素:8 =============反射修改数组长度================= 数组长度为:10 8 2 3 4 5 6 null null null null