zoukankan      html  css  js  c++  java
  • 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());
    
        }
    
    }
    设置任意对象的任意属性值
  • 相关阅读:
    JVM内存模型
    学习Spring Boot:(十九)Shiro 中使用缓存
    学习Spring Boot:(十八)Spring Boot 中session共享
    学习Spring Boot:(十七)Spring Boot 中使用 Redis
    学习Spring Boot:(十六)使用Shiro与JWT 实现认证服务
    学习Spring Boot:(十五)使用Lombok来优雅的编码
    学习Spring Boot:(十四)spring-shiro的密码加密
    学习Spring Boot:(十三)配置 Shiro 权限认证
    学习Spring Boot:(十二)Mybatis 中自定义枚举转换器
    学习Spring Boot:(十一) 自定义装配参数
  • 原文地址:https://www.cnblogs.com/wqbin/p/11215934.html
Copyright © 2011-2022 走看看