JAVA 反射机制是在运行状态中,对于任意一个类,都可以知道这个类的全部属性和方法;对于任意一个对象,都可以调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。java
简单来讲就是反射就是将 Java 类中的各类成分映射成一个个的 Java 对象。mysql
假若有两个程序员,一个程序员在写程序的时须要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码是不能经过编译的。此时,利用 Java 反射的机制,就可让第一个程序员在没有获得第二个程序员所写的类的时候,来完成自身代码的编译。程序员
Java 的反射机制它知道类的基本结构,这种对 Java 类结构探知的能力,咱们称为Java 类的“自审”。例如 一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术能够对一个类进行解剖,把个个组成部分映射成一个个对象。在 Java 中万物皆是对象,反射也是面向对象思想的一种体现。spring
首先 咱们来建立一个 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对象以及它的方法,算是初步对反射有了必定的应用(后半部分的代码属于换汤不换药,就再也不赘述)。
它们的区别就是 Class.forName获得的class是已经完成初始化完成的,Classloder.loadClass获得的class是尚未连接的。
简单来讲就是 forName方法会执行类中静态代码块中的内容,而 loadClass不会执行,咱们举一个简单的例子。
以 Class.forName("com.mysql.jdbc.Driver") 为例; Driver 类中有须要执行静态代码块(new Driver) 因此要用forname 不能loadclass。而springIoc 在读取bean的配置的时候 采起的是lazyloading(延时加载)的策略,使用 classloader 不须要执行静态代码块能够加快初始化速度,把相关加载留到真正执行代码的时候再操做。因此说这两种方法各有优劣,须要根据实际状况而定。
在本文中咱们讲到了 Java 反射的相关内容,但愿你看完本文后有所收获。