• java中的反射机制


    前言:

    ​ 相信很多人都知道反射可以说是Java中最强大的技术了,它可以做的事情太多太多,很多优秀的开源框架都是通过反射完成的,比如最初的很多注解框架,后来因为java反射影响性能,所以被运行时注解APT替代了,java反射有个开源框架jOOR相信很多人都用过,不过我们还是要学习反射的基础语法,这样才能自己写出优秀的框架,当然这里所讲的反射技术,是学习Android插件化技术、Hook技术等必不可少的!

    概述:

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
    要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

    以上的总结就是什么是反射
    反射就是把java类中的各种成分映射成一个个的Java对象
    例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。(其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)
    如图是类的正常加载过程:反射的原理在与class对象。
    熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。

    img

    主要作用

    通过反射可以使程序代码访问装载到JVM 中的类的内部信息,获取已装载类的属性信息,获取已装载类的方法,获取已装载类的构造方法信息

    常用方法

    (1)创建Student类

    package cn.tedu.reflection;
    //测试 反射
    public class Student {
     public String name = "皮皮霞";
     public int age = 22 ;
        //提供构造方法-右键-generate...constructor...
        public Student() {
        }
        public Student(String name) {
            this.name = name;
        }
        public Student(int age) {
            this.age = age;
        }
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    `public void show(){
            System.out.println("show()...");
        }
        public void test(String n){
            System.out.println("test()..."+n);
        }
        //为了能查看属性值,而不是地址值,提供重写的toString()
        //右键-generate...toString()-ok
        @Override
        public String toString() {
            return "Student{" +
                    "name='" + name + ''' +
                    ", age=" + age +
                    '}';
        }
    }
    

    (2)创建测试类

    package cn.tedu.reflection;
     
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    import java.util.Arrays;
    //测试 反射
    public class Test1_Reflect {
        public static void main(String[] args) throws Exception {
            //method();//通过反射的技术,获取Class对象
    //        method2();//通过反射的技术,获取类中的所有构造方法
    //        method3();//通过反射的技术,获取成员方法
    //        method4();//通过反射的技术,获取成员变量
            method5();//通过反射的技术,创建实例
        }
        //通过反射的技术,创建实例
        private static void method5() throws Exception {
            //1,获取Class对象
            Class<Student> clazz = Student.class;
            //2,创建实例
            //newInstance()--会触发构造方法--触发无参构造
            Student s = clazz.newInstance();
            //s = Student{name='皮皮霞', age=22}
            System.out.println("s = " + s);
     
            //3,需求:可以触发含参构造吗?可以-但是你得指定想要触发哪个含参构造
            // --参数是class对象类型,和含参构造的参数类型匹配
            //public Student(String name){} -- new Student("jack");
            Constructor<Student> c = clazz.getConstructor(String.class);
            Student s2 = c.newInstance("jack");
            //s2 = Student{name='jack', age=22}
            System.out.println("s2 = " + s2);
        }
        //通过反射的技术,获取成员变量
        private static void method4() throws ClassNotFoundException {
            //1,获取Class对象
            Class<?> clazz = Class.forName("cn.tedu.reflection.Student");
            //2,获取成员变量--!!!!只能获取public的!!!!
            Field[] fs = clazz.getFields();
            //3,遍历数组,获取每个Field
            for (Field f : fs) {
                //获取变量名
                System.out.println( f.getName() );
                //获取变量类型
                System.out.println( f.getType().getName() );
            }
        }
        //通过反射的技术,获取成员方法
        private static void method3() {
            //1,获取Class对象
            Class clazz = Student.class;
            //2,获取成员方法们
            Method[] ms = clazz.getMethods();
            //3,遍历数组,获取每个Method
            for (Method m : ms) {
                //获取方法名
                System.out.println(m.getName());
                //获取方法参数
                Class<?>[] cs = m.getParameterTypes();
                System.out.println( Arrays.toString(cs) );
            }
        }
        //通过反射的技术,获取类中的构造方法
        private static void method2() {
            //1,获取Class对象
            Class<Student> clazz = Student.class;
            //2,获取构造方法们
            Constructor<?>[] cs = clazz.getConstructors();
            //3,foreach循环获取每个构造方法
            for (Constructor<?> c : cs) {
                //获取构造方法名
                System.out.println(c.getName());
                //获取构造方法的参数
                Class<?>[] cs2 = c.getParameterTypes();
                System.out.println(Arrays.toString(cs2));
            }
        }
        //通过反射的技术,获取Class对象//三种方式
        private static void method() throws ClassNotFoundException {
    //        -- static Class<?> forName(String className)--参数是类的全路径
            Class<?> clazz = Class.forName("java.lang.Object");
    //        -- 类名.class
            Class<String> clazz2 = String.class;
    //        -- 对象.getClass()--泛型上限,最大是String类型,约束了元素的类型<=String类型
            Class<? extends String> clazz3 = new String().getClass();
     
            System.out.println("clazz = " + clazz);
            System.out.println("clazz2 = " + clazz2);
            System.out.println("clazz3 = " + clazz3);
        }
    }
    

    暴力反射

    暴力的获取类中的私有资源顺便获取公开的。
    暴力反射和普通反射的反射原理是一样的,都是拿到.class文件中的所有数据并封装成Class对象,通过各种方法来操作数据,只不过是换了一套API

    反射机制的优缺点

    优点:

    反射提高了Java程序的灵活性和扩展性,降低耦合性,提高自适应能力。它允许程序创建和控制任何类的对象,无需提前硬编码目标类;反射是其它一些常用语言,如C、C++、Fortran 或者Pascal等都不具备的

    缺点:

    • 性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此Java反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。

    • 使用反射会模糊程序内部逻辑:程序人员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂。

  • 相关阅读:
    【Atcoder】CODE FESTIVAL 2017 qual C D
    【BZOJ】4756: [Usaco2017 Jan]Promotion Counting
    【Luogu】P3933 Chtholly Nota Seniorious
    【BZOJ】1914: [Usaco2010 OPen]Triangle Counting 数三角形
    【算法】计算几何
    【BZOJ】1774: [Usaco2009 Dec]Toll 过路费
    【BZOJ】2200: [Usaco2011 Jan]道路和航线
    【BZOJ】1833 [ZJOI2010]count 数字计数
    【BZOJ】1731: [Usaco2005 dec]Layout 排队布局
    【BZOJ】1577: [Usaco2009 Feb]庙会捷运Fair Shuttle
  • 原文地址:https://www.cnblogs.com/ma159753/p/14209670.html
Copyright © 2020-2023  润新知