反射的概念和原理
类字节码文件是在硬盘上存储的,是一个个的.class文件。我们在new一个对象时,JVM会先把字节码文件的信息读出来放到内存中,第二次用时,就不用在加载了,而是直接使用之前缓存的这个字节码信息。 字节码的信息包括:类名、声明的方法、声明的字段等信息。在Java中“万物皆对象”,这些信息当然也需要封装一个对象,这就是Class类、Method类、Field类。 通过Class类、Method类、Field类等等类 可以得到 这个类字节码的全部信息,甚至可以不用new关键字就创建一个实例,可以执行一个对象中的方法,设置或获取字段的值,这就是反射技术。 注意:在反射技术中一个类的任何成员都有对应 的类进行描述。 比如: 成员变量(Field) 方法----> Method类 |
Class类
Class类解释说明:
Java中有一个Class类用于代表某一个类的字节码。通过获取这个class类的对象,就可以得到字节码的一些信息 |
得到class对象的三种方法
Java提供了三种方式获取类的字节码 forName():forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装(推荐使用这个,一般配合配置文件读取类的全名 创建对象) 类名.class 对象.getClass() |
例子:
Person类,用于被测试的类
package cn.itcast.reflect; public class Person { private int id; String name; public Person(int id,String name){ this.id = id; this.name = name; } public Person(){} private Person(int id){ this.id = id; } public void eat(int num){ System.out.println(name+"吃很"+num+"斤饭"); } private static void sleep(int num){ System.out.println("明天睡上"+num+"小时"); } public static void sum(int[] arr){ System.out.println("长度是:"+ arr.length); } @Override public String toString() { return " 编号:"+ this.id +" 姓名:"+ this.name; } } |
获取class对象的代码:
public static void main(String[] args) throws ClassNotFoundException { //推荐使用: 获取Class对象的方式一 Class clazz1 = Class.forName("cn.itcast.reflect.Person"); System.out.println("clazz1:"+ clazz1); //获取Class对象的方式二: 通过类名获取 Class clazz2 = Person.class; System.out.println("clazz1==clazz2?"+ (clazz1==clazz2)); //获取Class对象的方式三 :通过对象获取 Class clazz3 = new Person(110,"狗娃").getClass(); System.out.println("clazz2==clazz3?"+ (clazz2==clazz3)); } |
打印结果:
clazz1:class cn.itcast.reflect.Person clazz1==clazz2?true clazz2==clazz3?true |
通过class对象获取一些信息
获取类的全名(包名+类名),类的简单名称(不带包名,只有类名),类的修饰符
API解释说明:
1. getName()类的名称(全名,全限定名) 2 getSimpleName()类的的简单名称(不带包名) 3. getModifiers(); 类的的修饰符 |
例子:
import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; //获取到对应的Class对象 Class clazz = Class.forName("cn.itcast.reflect.Person"); System.out.println("-----------获取类的全名------------"); //通过Class对象获取类的全名(包含 包名) String fullName = clazz.getName(); System.out.println(fullName); //通过class对象获取类名(不包含包名) String simpleName = clazz.getSimpleName(); System.out.println(simpleName); //通过class对象获取类的修饰符 int modifyName = clazz.getModifiers(); String retval = Modifier.toString(modifyName); System.out.println("Class Modifier = " + retval); |
打印结果:
-----------获取类的全名------------ cn.itcast.reflect.Person Person Class Modifier = public |
获取类的全部构造函数,私有的,公有的
API:
getConstructors()获取一个类的所有公共的构造方法 getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。 |
代码:
//通过Class对象获取对应的构造方法 Constructor[] constructors = clazz.getConstructors(); // getConstructors()获取一个类的所有公共的构造方法 for(Constructor constructor : constructors){ System.out.println(constructor); } System.out.println("\n-------------获取所有的构造方法,包括私有的-------------"); Constructor[] constructors2 = clazz.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。 for(Constructor constructor2 : constructors2){ System.out.println(constructor2); } |
打印的结果:
----------获取所有的公共构造方法-------------- public cn.itcast.reflect.Person() public cn.itcast.reflect.Person(int,java.lang.String) -------------获取所有的构造方法,包括私有的------------- private cn.itcast.reflect.Person(int) public cn.itcast.reflect.Person() public cn.itcast.reflect.Person(int,java.lang.String) |
获取指定的构造对象,然后new出一个对象(这个是不能new出private修饰的构造函数)
API:
newInstance方法构造对象,默认使用的是无参数的构造方法 举例:Object ins = clazz.newInstance(); getConstructor(参数类型的.class)获取单个指定的构造方法。 举例:clazz.getConstructor(int.class,String.class); 局限地方:不能获取private的构造函数 |
例子:
System.out.println("\n获取指定的构造方法,然后new出一个对象"); //newInstance方法构造对象,默认使用的是无参数的构造方法 Object ins = clazz.newInstance(); Person p = (Person) ins; System.out.println(p); //getConstructor 获取单个指定的构造方法。 clazz.getConstructor(int.class,String.class); Constructor constructor = clazz.getConstructor(int.class,String.class); // Person p2 = (Person) constructor.newInstance(999,"小城"); // newInstance()创建一个对象 System.out.println(p2); |
打印结果:
获取指定的构造方法,然后new出一个对象 编号:0 姓名:null 编号:999 姓名:小城 |
获取指定的私有构造函数
API:
getDeclaredConstructor 方法:获取指定的私有构造函数 |
例子:
System.out.println("\n获取指定的私有构造函数"); Constructor constructor1 = clazz.getDeclaredConstructor(int.class); System.out.println(constructor1); |
打印结果:
获取指定的私有构造函数 private cn.itcast.reflect.Person(int) |
暴力反射:
System.out.println("暴力反射"); Constructor constructor2 = clazz.getDeclaredConstructor(int.class); System.out.println(constructor2); constructor2.setAccessible(true);//设置为true表示可以进行暴力反射,强行用private 构造函数new对象 Person p3 =(Person) constructor2.newInstance(100); System.out.println(p3); |
打印结果:
暴力反射 private cn.itcast.reflect.Person(int) 编号:100 姓名:null |
获取构造函数的完整代码:
package cn.itcast.reflect; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; /* 如何通过Class对象获取构造方法。 */ public class Demo2 { public static void main(String[] args) throws Exception { //获取到对应的Class对象 Class clazz = Class.forName("cn.itcast.reflect.Person"); // System.out.println("-----------获取类的全名------------"); // //通过Class对象获取类的全名(包含 包名) // String fullName = clazz.getName(); // System.out.println(fullName); // // // //通过class对象获取类名(不包含包名) // String simpleName = clazz.getSimpleName(); // System.out.println(simpleName); // // //通过class对象获取类的修饰符 // int modifyName = clazz.getModifiers(); // String retval = Modifier.toString(modifyName); // System.out.println("Class Modifier = " + retval); // System.out.println("----------获取所有的公共构造方法--------------"); // // //通过Class对象获取对应的构造方法 // Constructor[] constructors = clazz.getConstructors(); // getConstructors()获取一个类的所有公共的构造方法 // for(Constructor constructor : constructors){ // System.out.println(constructor); // } // // System.out.println("\n-------------获取所有的构造方法,包括私有的-------------"); // Constructor[] constructors2 = clazz.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。 // for(Constructor constructor2 : constructors2){ // System.out.println(constructor2); // } // System.out.println("\n获取指定的构造方法,然后new出一个对象"); // // //newInstance方法构造对象,默认使用的是无参数的构造方法 // Object ins = clazz.newInstance(); // Person p = (Person) ins; // System.out.println(p); // // //getConstructor 获取单个指定的构造方法。 // clazz.getConstructor(int.class,String.class); // Constructor constructor = clazz.getConstructor(int.class,String.class); // // Person p2 = (Person) constructor.newInstance(999,"小城"); // newInstance()创建一个对象 // System.out.println(p2); // System.out.println("\n获取指定的私有构造函数"); // Constructor constructor1 = clazz.getDeclaredConstructor(int.class); // System.out.println(constructor1); // // System.out.println("暴力反射"); Constructor constructor2 = clazz.getDeclaredConstructor(int.class); System.out.println(constructor2); constructor2.setAccessible(true);//设置为true表示可以进行暴力反射,强行用private 构造函数new对象 Person p3 =(Person) constructor2.newInstance(100); System.out.println(p3); } } |
通过class类获取 字节码中的方法信息
获取全部的方法部分
Api详解:
getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。 getDeclaredMethods()//获取到所有的方法(私有的也有),但是不包含父类的方法。 |
例子:
//获取到对应的Class对象 Class clazz = Class.forName("cn.itcast.reflect.Person"); //获取到所有公共的方法 Method[] methods = clazz.getMethods(); // getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。 //Method[] methods = clazz.getDeclaredMethods(); //获取到所有的方法(私有的也有),但是不包含父类的方法。 for(Method method : methods){ System.out.println(method); } |
获取指定的方法,并执行它
API:
getMethod("eat", int.class);//获取指定的方法,但是不能获取私有的方法 getDeclaredMethod("sleep",int.class);////执行私有的方法 setAccessible(true);//设置访问权限允许访问 invoke(p, 6);//invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。 |
用法:
Person p = new Person(110,"狗娃"); //获取指定的方法,但是不能获取私有的方法 Method m = clazz.getMethod("eat", int.class); //invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。 m.invoke(p, 3); //执行私有的方法 Method m2 =clazz.getDeclaredMethod("sleep",int.class); //设置访问权限允许访问 m2.setAccessible(true); //静态的方法第一个参数写null,表示没有对象调用,类本身会调用 m2.invoke(p, 6); |
暴力反射:
//暴力反射,获取私有的方法,并执行它 Method m = clazz.getDeclaredMethod("sleep", int.class); System.out.println(m); m.setAccessible(true); m.invoke(p, 8); |
获取方法部分完整代码:
package cn.itcast.reflect; import java.lang.reflect.Method; /* 通过Class对象获取到对应的方法。 在反射技术中使用了Method类描述了方法的。 */ public class Demo3 { public static void main(String[] args) throws Exception { //获取到对应的Class对象 Class<?> clazz = Class.forName("cn.itcast.reflect.Person"); // //获取到所有公共的方法 // Method[] methods = clazz.getMethods(); // getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。 //// Method[] methods = clazz.getDeclaredMethods(); //获取到所有的方法(私有的也有),但是不包含父类的方法。 // for(Method method : methods){ // System.out.println(method); // } Person p = new Person(110,"狗娃"); // // //获取指定的方法,但是不能获取私有的方法 // Method m = clazz.getMethod("eat", int.class); // //invoke 执行一个方法。 第一个参数:方法的调用对象。 第二参数: 方法所需要的参数。 // m.invoke(p, 3); // // // //执行私有的方法 // Method m2 =clazz.getDeclaredMethod("sleep",int.class); // //设置访问权限允许访问 // m2.setAccessible(true); // //静态的方法第一个参数写null,表示没有对象调用,类本身会调用 // m2.invoke(p, 6); // Method m = clazz.getMethod("sum", int[].class); // m.invoke(p,new int[]{12,5,9}); //暴力反射,获取私有的方法,并执行它 Method m = clazz.getDeclaredMethod("sleep", int.class); System.out.println(m); m.setAccessible(true); m.invoke(p, 8); } } |
通过class对象获取到字段信息
代码;
public static void main(String[] args) throws Exception { //获取到对应的Class对象 Class clazz = Class.forName("cn.itcast.reflect.Person"); //获取 到所有的成员变量(包含私有的) // Field[] fields = clazz.getDeclaredFields(); // for(Field field : fields){ // System.out.println(field); // } Person p = new Person(); Field field = clazz.getDeclaredField("id"); //设置访问权限可以访问 field.setAccessible(true); field.set(p, 110); //第一个参数: 设置该数据 的成员变量, 第二个参数:属性值。 System.out.println(p); } |
反射API总结:
Class类
1. getName()类的名称(全名,全限定名) 2 getSimpleName()类的的简单名称(不带包名)
|
4.getConstructors()获取一个类的所有公共的构造方法 5.getDeclaredConstructors(); //获取到一个类的所有构造方法,包括私有的在内 。 |
6.newInstance方法构造对象,默认使用的是无参数的构造方法 举例:Object ins = clazz.newInstance(); 7.getConstructor(参数类型的.class)获取单个指定的构造方法。 举例:clazz.getConstructor(int.class,String.class); 局限地方:不能获取private的构造函数 |
8.getDeclaredConstructor 方法:获取指定的私有构造函数 |
方法部分 |
getMethods() 获取所有 的公共方法(不包括私有的)包括父类继承的。 getDeclaredMethods()//获取到所有的方法(私有的也有),但是不包含父类的方法。 |
getMethod("eat", int.class);//获取指定的方法,但是不能获取私有的方法 |
clazz.getDeclaredMethod("sleep",int.class);//执行私有的方法 m2.invoke(p, 6); //表示m2这个方法被p这个对象执行了,后面的参数是m2这个方法需要的参数 |
字段部分 1.获取公共字段 Field[] getFields() 2.获取指定参数的公共字段 Field getField(String name) 3.获取所有的字段 Field[] getDeclaredFields() 4.获取指定参数的字段,包括私用 Field getDeclaredField(String name) |
一般用getDeclaredConstructor方法进行获取构造函数,一般不获取private修饰的构造函数