反射
反射
1.1反射的概述
1.1.1什么是反射
反射是一种机制/功能,利用该机制/功能可以在程序运行过程中对类进行解剖并操作类中的构造方法,成员方法,成员属性。
1.1.2反射的应用场景
- 开发工具中写代码时的提示
开发工具之所能够把该对象的方法和属性展示出来就使用利用了反射机制对该对象所有类进行了解剖获取到了类中的所有方法和属性信息,这是反射在IDE中的一个使用场景。
- 各种框架的设计
以上三个图标上面的名字就是Java的三大框架,简称SSH。
这三大框架的内部实现也大量使用到了反射机制,所以要想学好这些框架,则必须要
求对反射机制熟练了。
1.1.3使用反射机制解剖类的前提
必须先要获取到该类的字节码文件对象,即Class类型对象。关于Class描述字节码
文件如下图所示:
说明:
- Java中使用Class类表示class文件。
- 任何一个class文件都是Class类的一个对象。
1.2获取Class对象的三种方式
1.2.1通过类名.class获取
User.java /** * 用户 * JavaBean */ public class User {
//项目开发中,字段和属性名相同
private int id;//编号 private String name;//姓名 private double sal;//薪水
public User(){}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getSal() { return sal; }
public void setSal(double sal) { this.sal = sal; }
} |
Demo01.java /** * 通过类名.class获取 */ public void test1(){ //String.class,int.class,void.class Class clazz = User.class; System.out.println(clazz); } |
1.2.2通过Object类的成员方法getClass()方法获取
Demo01.java /** * 通过Object类的成员方法getClass()方法获取 */ public void test2(){ //new String().getClass() //User user = new User(); //Class clazz = user.getClass(); //System.out.println(clazz); } |
1.2.3通过Class.forName("全限定类名")方法获取
Demo01.java /** * 通过Class.forName("全限定类名")方法获取 */ public void test3() throws Exception { //User类的全路径名,且User在当前项目中 //String str = "com.itheima.ref.User"; //通过String创建User对象 //Class clazz = Class.forName(str); //System.out.println(clazz); String str = "java.langx.String"; Class clazz = Class.forName(str); System.out.println(clazz); } |
1.3获取Class对象的信息
知道怎么获取Class对象之后,接下来就介绍几个Class类中常用的方法了。
1.3.1获取简单类名
String getSimpleName(); 获取简单类名,只是类名,没有包
Demo02.java /** * 获取简单类名 */ public void test1() throws Exception{ String str = "com.itheima.ref.User"; Class clazz = Class.forName(str); //获取该Class对象的简单类名 String simpleName = clazz.getSimpleName(); System.out.println(simpleName); } |
1.3.2获取完整类名
String getName(); 获取完整类名,包含包名 + 类名
Demo02.java /** * 获取完整类名 */ public void test2() throws Exception{ String str = "com.itheima.ref.User"; Class clazz = Class.forName(str); //获取包名+类名 String name = clazz.getName(); System.out.println(name); } |
1.3.3创建对象
T newInstance() ; 创建此 Class对象所表示的类的一个新实例。要求:类必须有
public的无参数构造方法
Demo02.java /** * 创建对象 */ public void test3() throws Exception{ String str = "com.itheima.ref.User"; Class clazz = Class.forName(str); //根据Class创建对象 Object obj = clazz.newInstance(); //如果obj的引用是User类型的话 if(obj instanceof User){ //强转 User user = (User) obj; System.out.println(user); } } |
1.4获取Class对象的Constructor信息
一开始在阐述反射概念的时候,我们说到利用反射可以在程序运行过程中对类进行
解剖并操作里面的成员。而一般常操作的成员:构造方法,成员方法,成员属性,
那么接下来看看怎么利用反射来操作这些成员以及操作这些成员能干什么,先来看
看怎么操作构造方法。而要通过反射操作类的构造方法,我们需要先知道一个
Constructor类。
1.4.1 Constructor类概述
Constructor是构造方法类,类中的每一个构造方法都是Constructor的对象,通过
Constructor对象可以实例化对象。
1.4.2 Class类中与Constructor相关方法
1. Constructor[] getConstructors()
获取所有的public修饰的构造方法
2. Constructor[] getDeclaredConstructors()
获取所有构造方法,包括privat修饰的
3. Constructor getConstructor(Class... parameterTypes)
根据参数类型获取构造方法对象,只能获得public修饰的构造方法
4. Constructor getDeclaredConstructor(Class... parameterTypes)
根据参数类型获取构造方法对象,包括private修饰的构造方法
1.4.3 Constructor类中常用方法
1. T newInstance(Object... initargs)
根据指定参数创建对象
2. void setAccessible(true)
暴力反射,设置为可以直接访问私有类型的构造方法
1.4.4示例代码
User.java /** * 用户 * JavaBean */ public class User {
//项目开发中,字段和属性名相同
private int id;//编号 private String name;//姓名 private double sal;//薪水
public User(){}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getSal() { return sal; }
public void setSal(double sal) { this.sal = sal; }
} |
Demo03.java /** * 获取Class对象的Constructor信息 */ public class Demo03 {
/** * 演示Constructor[] getConstructors() */ public void test1(){ //获取Class对象 Class clazz = User.class; Constructor[] cs = clazz.getConstructors(); for(Constructor c : cs){ System.out.println(c); } }
/** * 演示Constructor[] getDeclaredConstructors() */ public void test2(){ Class clazz = User.class; Constructor[] cs = clazz.getDeclaredConstructors(); for(Constructor c : cs){ System.out.println(c); } }
/** * 演示Constructor getConstructor(Class... parameterTypes) */ public void test3() throws Exception{ Class clazz = User.class; //获取User()构造器 Constructor c = clazz.getConstructor(null); System.out.println(c); }
/** * 演示Constructor getDeclaredConstructor(Class... parameterTypes) */ public void test4() throws Exception{ Class clazz = User.class; //获取private User(int id,String name) Constructor c = clazz.getDeclaredConstructor(int.class,String.class); System.out.println(c); }
/** * 演示T newInstance(Object... initargs) */ public void test5() throws Exception{ //Class clazz = User.class; //获取无参构造器 //参数一:参数的Class对象 //Constructor c = clazz.getConstructor(null); //使用无参构造器创建对象 //参数一:实际参数 //Object obj = c.newInstance(null); //System.out.println(obj);
Class clazz = User.class; //底层只能调用无参构造器 //Object obj = clazz.newInstance();
//获取User(int i) Constructor c = clazz.getConstructor(int.class); //创建对象 Object obj = c.newInstance(2018); System.out.println(obj); }
/** * 演示void setAccessible(true) */ public void test6() throws Exception{ Class clazz = User.class; //获取private User(int id,String name) Constructor c = clazz.getDeclaredConstructor(int.class,String.class); //在默认情况下,我们不得访问私有的构造器 //暴力反射 c.setAccessible(true); Object obj = c.newInstance(2018,"赵君"); //System.out.println(obj); }
public static void main(String[] args) throws Exception{ Demo03 test = new Demo03(); //test.test1(); //test.test2(); //test.test3(); //test.test4(); //test.test5(); test.test6(); }
} |
1.5获取Class对象的Method信息
操作完构造方法之后,就来看看反射怎么操作成员方法了。同样在操作成员方法
之前我们需要学习一个类:Method类。
1.5.1 Method类概述
Method是方法类,类中的每一个方法都是Method的对象,通过Method对象可以
调用方法。
1.5.2 Class类中与Method相关方法
1. Method[] getMethods()
获取所有的public修饰的成员方法,包括父类中
2. Method[] getDeclaredMethods()
获取当前类中所有的方法,包含私有的,不包括父类中
3. Method getMethod("方法名", 方法的参数类型... 类型)
根据方法名和参数类型获得一个方法对象,只能是获取public修饰的
4. Method getDeclaredMethod("方法名", 方法的参数类型... 类型)
根据方法名和参数类型获得一个方法对象,包括private修饰的
1.5.3 Method类中常用方法
1. Object invoke(Object obj, Object... args)
根据参数args调用对象obj的该成员方法
如果obj=null,则表示该方法是静态方法
2. void setAccessible(true)
暴力反射,设置为可以直接调用私有修饰的成员方法
1.5.4示例代码
User.java /** * 用户 * JavaBean */ public class User {
//项目开发中,字段和属性名相同
private int id;//编号 private String name;//姓名 private double sal;//薪水
public User(){}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getSal() { return sal; }
public void setSal(double sal) { this.sal = sal; }
} |
Demo04.java /** * 获取Class对象的Method信息 */ public class Demo04 {
/** * 演示Method[] getMethods() * JUnit单元测试 */ @Test public void test1() { Class clazz = User.class; Method[] ms = clazz.getMethods(); for(Method m:ms){ System.out.println(m); } }
/** * 演示Method[] getDeclaredMethods() */ @Test public void test2(){ Class clazz = User.class; Method[] ms = clazz.getDeclaredMethods(); for(Method m:ms){ System.out.println(m); } }
/** * 演示Method getMethod("方法名", 方法的参数类型... 类型) */ @Test public void test3() throws Exception{ Class clazz = User.class; //参数一:方法名 //参数二:方法名中参数的Class类型,如果无的话,书写null Method m = clazz.getMethod("set",null); System.out.println(m); }
/** * 演示Method getDeclaredMethod("方法名", 方法的参数类型... 类型) */ @Test public void test4() throws Exception{ Class clazz = User.class; Object obj = clazz.newInstance(); Method m = clazz.getDeclaredMethod("show",null); System.out.println(m); }
/** * 演示Object invoke(Object obj, Object... args) */ @Test public void test5() throws Exception{ Class clazz = User.class; Object obj = clazz.newInstance(); //参数一:方法名 //参数二:方法名中参数的Class类型,如果无的话,书写null Method m = clazz.getMethod("set",null); //调用方法 //参数一:对象 //参数二:实际参数,如果无的话,书写null m.invoke(obj,null); }
/** * 演示void setAccessible(true) */ @Test public void test6()throws Exception{ Class clazz = User.class; Object obj = clazz.newInstance(); Method m = clazz.getDeclaredMethod("show",null); //暴力反射 m.setAccessible(true); m.invoke(obj,null); }
} |
1.6获取Class对象的Field信息
1.6.1 Field类概述
Field是属性类,类中的每一个属性都是Field的对象,通过Field对象可以
给对应的属性赋值和取值。
1.6.2 Class类中与Field相关方法
1. Field[] getFields()
获取所有的public修饰的属性对象,返回数组
2. Field[] getDeclaredFields()
获取所有的属性对象,包括private修饰的,返回数组
3. Field getField(String name)
根据属性名获得属性对象,只能获取public修饰的
4. Field getDeclaredField(String name)
根据属性名获得属性对象,包括private修饰的
1.6.3 Field类中常用方法
set通用方法都是给对象obj的属性设置使用
get通用方法是获取对象obj对应的属性值的
void setAccessible(true);暴力反射,设置为可以直接访问私有类型的属性
1.6.4 示例代码
User.java /** * 用户 * JavaBean */ public class User {
//项目开发中,字段和属性名相同
private int id;//编号 private String name;//姓名 private double sal;//薪水
public User(){}
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getSal() { return sal; }
public void setSal(double sal) { this.sal = sal; }
} |
Demo05.java /** * 获取Class对象的Field信息 */ public class Demo05 {
/** * 演示Field[] getFields() */ @Test public void test1() throws Exception{ Class clazz = User.class; Field[] fs = clazz.getFields(); for (Field f : fs) { System.out.println(f); } }
/** * 演示Field[] getDeclaredFields() */ @Test public void test2()throws Exception{ Class clazz = User.class; Field[] fs = clazz.getDeclaredFields(); for (Field f : fs) { System.out.println(f); } }
/** * 演示Field getField(String name) */ @Test public void test3()throws Exception{ Class clazz = User.class; //获取某个Field对象 //参数一:字段名 Field f = clazz.getField("id"); System.out.println(f); }
/** * 演示Field getDeclaredField(String name) */ @Test public void test4()throws Exception{ Class clazz = User.class; Field f = clazz.getDeclaredField("sal"); System.out.println(f); }
/** * 演示set/get() */ @Test public void test5()throws Exception{ Class clazz = User.class; Object obj = clazz.newInstance(); //获取某个Field对象 //参数一:字段名 Field f = clazz.getField("id"); //为id字段设置值 //参数一:对象 //参数二:实际值 f.setInt(obj,2018); //从id字段中获取值 System.out.println(f.getInt(obj)); }
/** * 演示void setAccessible(true) */ @Test public void test6()throws Exception{ Class clazz = User.class; Object obj = clazz.newInstance(); //f指向私有成员变量 Field f = clazz.getDeclaredField("sal"); //暴力反射 f.setAccessible(true); f.setDouble(obj,5555.55); System.out.println(f.getDouble(obj));
}
} |