龙空技术网

大厂面试系列-关于Java反射机制你了解哪些内容

从程序员到架构师 26845

前言:

此刻我们对“java 遍历类的成员属性”都比较着重,看官们都需要知道一些“java 遍历类的成员属性”的相关资讯。那么小编在网摘上搜集了一些有关“java 遍历类的成员属性””的相关文章,希望你们能喜欢,朋友们一起来学习一下吧!

反射机制

关于反射机制,是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键。

想要了解关于Java反射机制的内容我们还需要了解一个类,这个类就是Class类。

Class类

我们都知道Java是标准的面向对象的编程语言,在我们学习Java编程语言之初我们就知道在Java中一切皆对象的概念。那么我们下面介绍的Class类其实就是对Java中所有的.class后缀文件的一个抽象。也是反射机制产生的基础支持。

在Java中Class是一个比较特殊的类,它的作用是用来封装所有可以被JVM加载的Java类对象,包括接口、类、注解等等。在我们的类对象被加载到JVM中的时候,在JVM中便会产生一个与之关联的Class对象,这个对象包含了我们加载类的很多信息。包括属性、方法、注解等等,可以通过这个Class对象对被装入类的详细信息进行访问。

了解类加载机制的人都知道,在Java虚拟机中为每种类型管理一个独一无二的Class对象。而这里所说的独一无二则是通过类路径、包路径、全类名等方式来进行标识。也就是说,每个类(型)都有一个Class对象。

也就是说,我们可以通过反射机制完成很多的操作。而且在我们的Object类中也提供了如下的方法

public final native Class<?> getClass();

这个方法其实就是用来获取我们对应对象的Class对象的。根据前面的介绍通过Class可以完成很多的操作。

Java反射机制

在之前的文章中我们通过反射机制获取了HashMap容量以及存入数据的大小等内容。而这些属性内容,在HashMap中并没有提供对应的访问接口。对于容量、大小这些内容都是在运行时才有的东西。也就是说如果我们想在运行的时候获取到某个类对应的Class文件相关的内容就可以使用反射机制来进行操作。

我们知道Java代码在通过编译之后会生成一个.class的文件。而这个.class文件其实就是原来的.java 文件对应的字节码文件。从某种意义上来讲,它们是一样的。所说,既然在运行的过程中JVM只认.class文件,那么我们何不通过.class文件来对对象进行操作呢?

关于反射机制,官方给出的概念:反射是Java语言的一个特性,它允许程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个Java类获取它所有的成员变量和方法并且显示出来。

而通过上面的介绍我们可以将反射理解为一种动态可修改对象的一种能力。也就是说我们在运行的时候可以获取对象,对对象信息进行修改,因为按照之前的说法,反射机制可以获取到任何的在JVM运行的.class文件的所有信息。

反射机制的优缺点

通过反射机制我们可以实现动态的对象创建和编译,可以在不依赖的第三方依赖的情况下通过反射机制创建对象。这样做更有利于面向对象语言的编程,但随之带来的问题也是存在的。就是对于系统性能的消耗。

因为反射其实就是对JVM提供一种新的解释机制,可以这样理解,我们Java语言是一种编译性的语言通过编译之后生成字节码文件,然后交给JVM解释运行,但是反射机制打破了这种规则,它是直接来向JVM提供一套符合规则的字节码文件规则。然后让JVM解释运行。这样做反而是增加了JVM的负担。也就是原本约定好的规则,临时发生了变化,就会导致原本原本准备好的资源已经不再适配class的运行,就要准备其他的资源进行支持。

反射机制的应用

在Spring框架中为了建立控制反转机制,大量的使用了反射来进行对象的创建。下面来看一段比较经典的代码。

interface fruit{     public abstract void eat();}class Apple implements fruit{public void eat(){         System.out.println("Apple");     }}class Orange implements fruit{public void eat(){        System.out.println("Orange");    }}class Factory{    public static fruit getInstance(String ClassName){        fruit f=null;        try{            f=(fruit)Class.forName(ClassName).newInstance();        }catch (Exception e) {            e.printStackTrace();        }        return f;    }}class hello{    public static void main(String[] a){        fruit f=Factory.getInstance("Reflect.Apple");        if(f!=null){            f.eat();        }    }}

在上面代码中使用了工厂设计模式与反射机制的结合来创建Fruit对象。而通过上面的配置我们可以知道,传入的String ClassName可以是任何Frist类的子类对象路径。也就是说只要我们需要,我们就可以通过类路径的方式通过反射机制来实现对象向的创建。

IOC容器中是如何使用反射的

Spring框架底层支持的两大技术一个是IOC,一个是DI。也就是是我们常说的依赖注入和控制反转。而其中使用了大量的反射。这是为了提高配置的灵活性,同时也是在另一个方面提高了编程效率。使用者不需要在调用的时候对对象进行创建,而是将所有的对象的管理都交给了容器,而容器完成的操作就是将所有需要的对象通过反射机制创建到容器中。

我们可以将IOC操作看作上面代码中展示的工厂模式的一种优化操作。在这个优化操作中通过各种工厂,各种动态代理,各种反射机制,将应用中所要用到的所有对象都托管到容器中,在使用的时候从容器中直接获取即可,简化了大量的编程内容,大大的提升了开发效率。

在使用了IOC之后,对于第三方组件,通过反射机制达到了低侵入式的目的,在之前介绍关于Spring Boot底层源码的时候,我们介绍过一个注解@Import 注解。有兴趣的读者可以了解一下关于@Import注解相关的内容。

总结

反射机制是Java提供的一个强大机制,能够使得我们更加方便快捷的创建代码,为运行是修改代码提供了解决方案,可以在一些提前不知道类名、不知道逻辑的情况下引入第三方的依赖来支持业务逻辑的实现。但是如果在项目中反射机制应用的不好,也会导致系统性能的急剧下降。从而带来负面的影响。

标签: #java 遍历类的成员属性