谈一谈Java中的反射机制

什么是反射?

JAVA 反射机制是在运行状态中,对于任意一个类,都可以知道这个类的全部属性和方法;对于任意一个对象,都可以调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。java

简单来讲就是反射就是将 Java 类中的各类成分映射成一个个的 Java 对象。mysql

在咱们了解了反射的基本概念以后,天然而然的咱们就提出了如下问题,反射有什么用?

假若有两个程序员,一个程序员在写程序的时须要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码是不能经过编译的。此时,利用 Java 反射的机制,就可让第一个程序员在没有获得第二个程序员所写的类的时候,来完成自身代码的编译。程序员

Java 的反射机制它知道类的基本结构,这种对 Java 类结构探知的能力,咱们称为Java 类的“自审”。例如 一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术能够对一个类进行解剖,把个个组成部分映射成一个个对象。在 Java 中万物皆是对象,反射也是面向对象思想的一种体现。spring

说了这么多,感受 好像仍是云里雾里。那接下来就开始 show code。

首先 咱们来建立一个 Robot 类。sql

public class Robot {
    private String name;


    public void sayHi(String helloSentence) {
        System.out.println(helloSentence + " " + name);
    }


    private String throwHello(String tag) {
        return "Hello " + tag;
    }


}
复制代码

如代码所示,咱们定义了一个私有的成员变量以及两个方法。bash

接下来咱们就经过反射来获取它。ui

public class ReflectSample {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {

        Class rc = Class.forName("com.interview.javabasic.reflect.Robot");
        Robot r = (Robot) rc.newInstance();
        System.out.println("Class name is " + rc.getName());
        Method getHello = rc.getDeclaredMethod("throwHello", String.class);
        getHello.setAccessible(true);
        Object str = getHello.invoke(r, "Bob");
        System.out.println("getHello result is " + str);
        Method sayHi = rc.getMethod("sayHi", String.class);
        sayHi.invoke(r, "Welcome");
        Field name = rc.getDeclaredField("name");
        name.setAccessible(true);
        name.set(r, "Alice");
        sayHi.invoke(r, "Welcome");


    }
}

复制代码

首先咱们建立一个 Class对象 rc,而且经过 forName方法来给它赋值。这里我先给你提一个小问题,loadClass 和 forName 的区别,你能够先思考一下,答案会在文末给出。spa

接着咱们的例子,咱们经过 newInstance() 方法来创造一个实例,而且其强转为Robot对象。 紧接着咱们输出 rc 的 name,rc 是经过咱们传递的路径获得的,因此 name 天然是咱们但愿建立的 Robot 类。code

咱们经过 rc.getDeclaredMethod()方法获得了一个method对象,方法的参数对应着咱们但愿获得方法的名称。因为该方法是私有方法,因此咱们 将 setAccessible() 设为true,表示反射在应用的时候,不会去进行权限检查。对象

因为 throwHello方法须要参数,咱们就传入了Bob,最后输出的结果是 getHello result is Hello Bob

经过上述的代码,咱们获得了 Robot对象以及它的方法,算是初步对反射有了必定的应用(后半部分的代码属于换汤不换药,就再也不赘述)。

最后,咱们来解答文中的问题 loadClass和forName有什么区别?

它们的区别就是 Class.forName获得的class是已经完成初始化完成的,Classloder.loadClass获得的class是尚未连接的。

简单来讲就是 forName方法会执行类中静态代码块中的内容,而 loadClass不会执行,咱们举一个简单的例子。

以 Class.forName("com.mysql.jdbc.Driver") 为例; Driver 类中有须要执行静态代码块(new Driver) 因此要用forname 不能loadclass。而springIoc 在读取bean的配置的时候 采起的是lazyloading(延时加载)的策略,使用 classloader 不须要执行静态代码块能够加快初始化速度,把相关加载留到真正执行代码的时候再操做。因此说这两种方法各有优劣,须要根据实际状况而定。

在本文中咱们讲到了 Java 反射的相关内容,但愿你看完本文后有所收获。

相关文章
相关标签/搜索