一、背景
最近的项目中需要使用到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