反射知识梳理

简介: 反射知识梳理

笔记


码云上的笔记


https://gitee.com/hufanglei/study/raw/master/%E5%8F%8D%E5%B0%84%E7%AC%94%E8%AE%B0/%E5%8F%8D%E5%B0%84.pdf


腾讯文档上的笔记


https://docs.qq.com/pdf/DWklmY0xUUmh2WUxu


代码:


https://gitee.com/hufanglei/study/tree/master/code/reflect-demo


反射


1.根据包名如何获取包下的类的信息并能调用类的信息?


Q: 原理根据文件夹路径获取路径下的文件。


具体操作:


将包名的.替换成/,得到文件路径


获取文件路径下的类的名称


根据名称+.class得到Class对象


根据该类的Class对象获取类的内部信息,然后调用方法,成员变量等。


2.反射有什么好处,并举例说明


Q: new Object获取对象是静态编译,反射是动态编译。反射提高了程序的扩展性。new对象调用的前提(编译需要)是必须内存有这个对象(.class字节码),反射是根据.class字节码文件生成对象,并调用。才可以调用,反射可以没有这个对象甚至没有class文件,用的时候再根据class文件名去查找class文件强制加载这个对象并调用。比较灵活。


我们封装框架的时候,如tomcat并不知道你写了多少个servlet,但是他可以吧你的servlet在程序启动的时候给调用,为啥呢?因为我们可以根据web.xml或者注解方式把文件的包名,类名等给了tomcat,tomcat启动的时候,扫描这些配置,然后加载到内存中就可以使用了。


我们只要关注注解或web.xml对应的类信息(通常是包名+类名),用反射方式获取的信息就可以了。这就是反射扩展性的一个例子。


3.获取字节码对象的三种方式


 

public static void main(String[] args) throws ClassNotFoundException {
//        test1();
//        test2();
          test3();
    }
    /**
     * 方式3
     * 包名 class
     * 只要通过给定的类的 字符串名称就可获取该类,更为扩展
     * 可是用class类中的方法完成, 该方法就是forName    
     */
    private static void test3() throws ClassNotFoundException {
        Class<?> classz = Class.forName("com.example.reflect.bean.Person");
        System.out.println(classz);
        Class<?> classz2 = Class.forName("com.example.reflect.bean.Person");
        System.out.println(classz2);
        System.out.println(classz == classz2);
    }
    /**
     * 方式2:
     * 类名.class
     * 任何数据类型都具备一个静态的属性,class类来获取其对应的class对象
     * 相对简单,但是还是要明确用到类中的静态成员
     * 还是不够扩展
     */
    private static void test2() {
        Class<?> classz = Person.class;
        System.out.println(classz);
        Class<?> classz2 = Person.class;
        System.out.println(classz2);
        System.out.println(classz==classz2);
    }
    /**
     * 方式1:
     * getClass()
     * Object类中的getClass()方法。
     * 这种方式,必须要明确具体的类并创建对象,麻烦
     */
    private static void test1() {
        Person person = new Person();
        Class<?> classz = person.getClass();
        System.out.println(classz);
        Class<?> classz2 = person.getClass();
        System.out.println(classz2);
        System.out.println(classz == classz2);
    }


4.反射获取实例对象的两种方式


早期: new时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内存

并创建该字节码文件对象,并接着创建该字节码文件的对应的Person对象。

现在,找寻该名称类文件,并加载进内存,并产生class对象,通过下面产生类的对象


第一种: 通过Class对象的newInstance方法,只能获取无参数的构造函数的实例


第二种:根据Class的属性Construct对象的newIntance(…)方法,获取有参数的构造函数,并实例化


/**
     * 第二种方式: 根据Construcat对象的newInstance方法获取对象
     * 当获取指定名称对应类中的
     *
     * 当获取指定名称对应类中的所体现的对象时,而改对象初始化不适用空参构造该怎么办?
     * 既然是通过指定的构造函数进行对象的初始化
     * 所以应该先获取到该构造函数,通过字节码文件对象即可完成
     * 该方法是: getConstructor(paramterTypes)
     */
    private static void createObect2() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        String name = "com.example.reflect.bean.Person";
        Class<?> clazz = Class.forName(name);
        Constructor<?> constructor = clazz.getConstructor( String.class, int.class);
        Person p = (Person) constructor.newInstance("小强",18);
        p.show();
    }
    //第一种方式
    //获取无参的是实例对象
    private static void createObect1() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        String name = "com.example.reflect.bean.Person";
        Class<?> clazz = Class.forName(name);
        Object o = clazz.newInstance();
        Person p = (Person) o;
       p.show();
    }


5.获取Class中的字段


Class类获取字段有4个方法:


演示一个获取可以获取私有字段的单个字段的方法:getDeclaredFiled(String name)


private static void getFieldDemo() throws NoSuchFieldException, ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class<?> clazz = Class.forName("com.example.reflect.bean.Person");
        Field field = clazz.getDeclaredField("age");
        //对私有字段的访问取消权限检查,暴力访问
        field.setAccessible(true);
        Object object = clazz.newInstance();
        //设置值
        field.set(object, 19);
        Object o = field.get(object);
        System.out.println(o);
    }


6.获取class中的方法


无参的方法的调用


private static void getMethodDemo() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<?> clazz = Class.forName("com.example.reflect.bean.Person");
        Method[] methods = clazz.getMethods(); //获取的都是公有的方法
        for (Method method : methods) {
            System.out.println(method.getName());
        }
        System.out.println("-----------------------");
        //只拿本类中的包括私有的
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            System.out.println(method.getName());
        }
        System.out.println("-----------------------");
        //获取空参数一般方法
        Method method = clazz.getMethod("show", null);
        //Object object = clazz.newInstance();
        Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, int.class);
        Object o = constructor.newInstance("小王", 25);
        method.invoke(o, null);
    }


有参数的方法的调用


private static void getMethodDemo1() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        Class<?> clazz = Class.forName("com.example.reflect.bean.Person");
        //获取空参数一般方法
        Method method = clazz.getMethod("paramMethod", String.class, int.class);
        Object object = clazz.newInstance();
        method.invoke(object, "小强", 23);
    }


7.反射调用类,增强扩展性的例子


public interface PCI {
    void open();
    void close();
}


public class SoundPCI implements PCI {
    @Override
    public void open() {
        System.out.println("SoundP open");
    }
    @Override
    public void close() {
        System.out.println("SoundP close");
    }
}


public class NetCard implements PCI{
    @Override
    public void open() {
        System.out.println("NetCard open");
    }
    @Override
    public void close() {
        System.out.println("NetCard close");
    }
}


public class Mainboard {
    public void run() {
        System.out.println("main board run....");
    }
    public void userPCI(PCI p) {
        if (p != null) {
            p.open();
            p.close();
        }
    }
}


public class ReflectTest {
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException {
        Mainboard mainboard = new Mainboard();
        mainboard.run();
        // mainboard.userPCI(new SoundPCI());
        //通过反射调用pci
        usePCI(mainboard);
    }
    private static void usePCI(Mainboard mainboard) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException {
//        File file = new File("pci.properties");
        Properties props = new Properties();
        InputStream in = ReflectTest.class.getClassLoader().getResourceAsStream("pci.properties");
        props.load(in);
        for (int i = 0; i < props.size(); i++) {
            String pciName = props.getProperty("pci" + (i + 1));
            Class clazz = Class.forName(pciName);
            PCI p = (PCI) clazz.newInstance();
            mainboard.userPCI(p);
        }
    }
}



相关文章
|
2月前
|
安全 Java 数据库连接
如何理解反射
反射之所以被称为框架的灵魂,主要是因为它赋予了我们在运行时分析类以及执行类中方法的能力。通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。
75 5
|
5月前
|
存储 Java 开发者
抽象类和接口,你不知道的秘密!Java编程新视角
抽象类和接口,你不知道的秘密!Java编程新视角
45 5
|
6月前
|
Java
类信息的“隐形守护者”:JAVA反射技术全揭秘
【7月更文挑战第1天】Java反射技术是动态获取类信息并操作对象的强大工具。它基于Class对象,允许在运行时创建对象、调用方法和改变字段。例如,通过`Class.forName()`动态实例化对象,`getMethod()`调用方法。然而,反射可能破坏封装,影响性能,并需处理异常,故使用时需谨慎。它是Java灵活性的关键,常见于框架设计中。
40 0
|
7月前
|
存储 Java 开发者
Java编程新视角:抽象类和接口,你不知道的秘密!
【6月更文挑战第17天】在Java中,抽象类与接口是抽象概念的关键工具。抽象类是不可实例化的模板,包含抽象和具体方法,适合有层次结构的继承;接口仅含抽象方法,像契约般规定实现类的行为,适用于无关对象间的统一接口。Java类单继承但可多实现接口,增加设计灵活性。理解并巧妙运用二者,能提升代码质量和可维护性。
32 0
|
XML 安全 Java
教你精通Java语法之第十三章、反射
Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到,那么,我们就可以修改部分类型信息;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射(reflection)机制。1. 反射的意义2. 反射重要的几个类: Class类 、Field类、 Method类、 Constructor类3. 学会合理利用反射,一定要在安全环境下使用。
76 0
|
安全 Java 测试技术
带你深入学习“反射”技术
带你深入学习“反射”技术
149 0
【C#本质论 八】类-从设计的角度去认知(多态)
【C#本质论 八】类-从设计的角度去认知(多态)
73 0
|
JSON API 数据格式
利用注解 + 反射消除重复代码,妙
利用注解 + 反射消除重复代码,妙
110 0
|
JSON API 数据格式
利用注解 + 反射消除重复代码,妙!
假设银行提供了一些 API 接口,对参数的序列化有点特殊,不使用 JSON,而是需要我们把参数依次拼在一起构成一个大字符串: 1)按照银行提供的API文档顺序,将所有的参数构成定长的数据,并且拼接在一起作为一整个字符串 2)因为每一种参数都有固定长度,未达到长度需要进行填充处理
172 0
|
Java C++
保守VS开放?看清封装对象属性 | 带你学《Java面向对象编程》之四
高楼万丈,起于平地。本节通过对比正反几个实例剖析了封装对象属性的必要性,介绍了进行封装的基本原则。
保守VS开放?看清封装对象属性   |  带你学《Java面向对象编程》之四