-
反射:reflect
1、类加载器
一个类如果想被使用,要先加载到内存中,一般会经过以下步骤,第二步还可以细分为三步。
类加载器用来把类的二进制文件加载到内存中,并在堆区生成一个与之对应的java.lang.Class对象.
类加载器通常由JVM提供,其加载的类文件的来源有以下几种:
- 从本地文件系统加载class文件
- 通过jar包加载class文件,例如jdbc数据库的驱动就是这种方式
- 通过网络加载class文件
- 动态编译源文件并加载
类加载器的组成层次:
- Bootstrap ClassLoader:根类加载器,负责Java运行核心类库的加载,比如:String,System等等,在jdk的jre中的lib目录下rt.jar中的类
- Extention ClassLoader:扩展类加载器,负责JRE扩展目录中jar包的加载,在jdk的jre中的lib目录下ext目录中的类
- System ClassLoader:系统类加载器(应用加载器),负责在JVM启动时加载来自java命令的-classpath中指定的类,和java.class.path系统属性中包含的类.
2、反射概述:reflect
简介:
反射就是把java类中的各种成分映射成一个个的Java对象
例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
反射的机制:
能通过一个Class对象操作类的成员,一旦能得到类的Class对象,就可以通过它来使用其所对应的类的任意成员变量,构造方法以及成员方法。
所以,Class对象中,最基本的应该包含三个方面内容:
- 成员变量:Field
- 构造方法:Constructor
- 成员方法:Method
反射与类加载的关系:
3、Class类
4、获取Class对象的三种方式
- Object类中的getClass()方法的返回值
- 类文件的class属性
- Class类的静态方法:Class.forName(“类名完整路径”)
eg:Class.forName(“com.test.Student”)
5、获取构造方法
获取所有或公共构造方法
public Constructor[] getConstructors()//获取所有的公共构造
public Constructor[] getDeclaredConstructors()//获取所有的构造
获取指定构造方法并使用
public Constructor getConstructor(Class... types)//获取指定的公共构造
public Constructor getDeclaredConstructor(Class... types)//获取指定的构造
Class c = Class.forName("com.test.Person"); Constructor con = c.getConstructor();//获取空参构造方法 Object obj = con.newInstance();//创建对象 Class c = Class.forName("com.Person"); Constructor con = c.getConstructor(String.class,int.class); Object obj = con.newInstance(“tom”,11); Class c = Class.forName(“com.Person”); Constructor con = c.getDeclaredConstructor(String.class); Object obj = con.newInstance(11);
5.1案例暴力破解私有方法

class Student { private String name; public int age; //各种权限的构造方法 public Student(){ System.out.println("空参构造"); } Student(String name){ this.name = name; System.out.println("带字符串的构造方法"); } public Student(int age){ this.age = age; System.out.println("带int的构造方法"); } private Student(Long l){ System.out.println("私有的构造方法被调用"); this.name = "zhangsan"; this.age = 20; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } // public void test1(){ System.out.println("无参无返回值方法"); } public void test2(int i){ System.out.println("有参无返回值方法"); } public String test3(String name){ System.out.println("有参有返回值方法"); return name; } private void test4(){ System.out.println("私有的无参无返回值方法"); } } import java.lang.reflect.Constructor; public class Demo2 { public static void main(String[] args) throws Exception { //获取Class对象 Class c1 = Class.forName("com.test11.reflect.Student"); //获取私有构造方法 Constructor con = c1.getDeclaredConstructor(Long.class); //(设置可访问性)暴力破解 con.setAccessible(true); //创建对象 Object obj = con.newInstance(10L); Student s = (Student) obj; System.out.println(s.getName() +"--"+ s.getAge()); } }
6、获取成员变量并使用
- getFields()//
- getDeclaredFields()
- getFiled(Sting name) //获取指定的公共字段
- getDeclaredFile(String name)//获取指定的字段
- set(Object obj,Object value) 给某个对象的本成员变量赋值为value
- setAccessible(boolean bool) //对成员变量(尤其私有成员变量)设置可访问性

import java.lang.reflect.Constructor; import java.lang.reflect.Field; /* * 成员变量的使用 */ public class Demo3 { public static void main(String[] args) throws Exception { // Class c = Class.forName("wang.Student"); Constructor con = c.getDeclaredConstructor(); Object obj = con.newInstance(); //获取所有的公共字段 // Field[] fields = c.getFields(); // for (Field f : fields) { // System.out.println(f); // } //结果:public int wang.Student.age //获取所有的字段 Field[] fields = c.getDeclaredFields(); for (Field f : fields) { System.out.println(f); } //结果: //private java.lang.String wang.Student.name //public int wang.Student.age //获取指定的字段 Field f = c.getDeclaredField("name"); //设置可访问性 f.setAccessible(true); //使用成员变量 f.set(obj, "李四"); //查看结果 System.out.println(((Student)obj).getName());//李四 } }
7、获取成员方法并使用
- getMethods():获取所有的公共成员方法
- getDeclaredMethods():获取所有成员方法
- getMethod(String name):获取指定的公共成员方法
- getDeclaredMethod(String name):获取指定的成员方法
- setAccessible(boolean bool)

import java.lang.reflect.Constructor; import java.lang.reflect.Method; /* * 成员方法的使用 */ public class Demo4 { public static void main(String[] args) throws Exception { Class c = Class.forName("com.test11.reflect.Student"); Constructor con = c.getDeclaredConstructor(); Object obj = con.newInstance(); //获取所有公共的成员方法 // Method[] ms = c.getMethods(); // for (Method m : ms) { // System.out.println(m); // } //获取所有成员方法 // Method[] ms = c.getDeclaredMethods(); // for (Method method : ms) { // System.out.println(method); // } //获取指定的方法 // Method m = c.getDeclaredMethod("test3", String.class); // //设置可访问性 // m.setAccessible(true); // //使用成员方法 // Object res = m.invoke(obj, "string"); // System.out.println(((String)res).toUpperCase()); //获取没有参数的方法并使用 Method m = c.getDeclaredMethod("test4"); m.setAccessible(true); Object res = m.invoke(obj);//没有返回值的方法,返回的是null System.out.println(res); } }
8、反射应用:加载配置文件内容并使用
法1:从配置文件中读取到类名
法2:使用类加载器的方式获取配置文件内容
法3:通过ResourceBundle获取配置文件内容
demo:配置文件 + 工厂模式 + 反射==》动态的修改实现类

import java.io.FileInputStream; import java.io.InputStream; import java.lang.reflect.Constructor; import java.util.Properties; import java.util.ResourceBundle; /* * 创建对象的工作由工厂来做 * */ public class AnimalFactory { //私有化构造方法,外界不能创建对象,只能通过静态方法获取Animal对象 private AnimalFactory(){} public static Animal getAnimal() throws Exception{ //法1:从配置文件中读取到类名 // Properties p = new Properties(); // p.load(new FileInputStream("config.txt")); // String className = p.getProperty("className"); //法2:使用类加载器的方式获取配置文件内容 // InputStream in = AnimalFactory.class.getClassLoader().getResourceAsStream("config.txt"); // Properties p = new Properties(); // p.load(in); // String className = p.getProperty("className"); //法3:通过ResourceBundle获取配置文件内容 ResourceBundle b = ResourceBundle.getBundle("a"); String className = b.getString("className"); //获取到类名对应的Class对象 Class c = Class.forName(className); //获取到空参构造方法并调用 Constructor con = c.getDeclaredConstructor(); Object obj = con.newInstance(); return (Animal)obj; } }
9、用反射越过泛型检查

import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Date; /* * 用反射越过集合的类型检查 */ public class Demo { public static void main(String[] args) throws Exception { ArrayList<String> list = new ArrayList<>(); list.add("abc"); // list.add(120); //通过反射越过类型检查 Class c = list.getClass(); //获取集合的原始的add方法 Method m = c.getDeclaredMethod("add",Object.class ); //方法的使用 m.invoke(list, "abc"); m.invoke(list, 123); m.invoke(list, new Date()); //遍历 for (Object obj : list) { System.out.println(obj); } } }
10、反射工具:设置任意对象的任意属性

/* * 设置任意对象的任意属性值 */ import java.lang.reflect.Field; class Tool{ private Tool(){} public static void set(Object obj,String name,Object value) throws Exception{ //获取实例对象的Class对象 Class c = obj.getClass(); //获取对应的成员变量 Field f = c.getDeclaredField(name); f.setAccessible(true); //设置属性 f.set(obj, value); } } public class Demo2 { public static void main(String[] args) throws Exception { Student s = new Student(); //通过工具设置私有成员变量的值 Tool.set(s, "name", "lisi"); // System.out.println(s.getName()); } }