java 反射

  • 反射: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());

    }

}
设置任意对象的任意属性值
原文地址:https://www.cnblogs.com/wqbin/p/11215934.html