吊打面试官系列:说说反射的用途及实现?

开发 后端
反射是Java程序开发语言的特征之一,它允许动态地发现和绑定类、方法、字段,以及所有其他的由于有所产生的的元素。通过反射,能够在需要时完成创建实例、调用方法和访问字段的工作。

 

反射是什么?

 

反射是Java程序开发语言的特征之一,它允许动态地发现和绑定类、方法、字段,以及所有其他的由于有所产生的的元素。通过反射,能够在需要时完成创建实例、调用方法和访问字段的工作。

反射机制主要提供功能

 

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的方法,通过反射甚至可以调用到private修饰的方法
  • 生成动态代理

反射在牛逼框架中的使用

 

  • Spring 框架的 IOC 基于反射创建对象和设置依赖属性。
  • Spring MVC 的请求调用对应方法,也是通过反射。
  • JDBC 的 Class#forName(String className) 方法,也是使用反射。

反射中,Class.forName 和 ClassLoader 区别?

 

这两者,都可用来对类进行加载。差别在于:

  • Class#forName(…) 方法,除了将类的 .class 文件加载到JVM 中之外,还会对类进行解释,执行类中的 static 块。
  • ClassLoader 只干一件事情,就是将 .class 文件加载到 JVM 中,不会执行 static 中的内容,只有在 newInstance 才会去执行 static 块。

反射的常用类

 

Java中反射相关的类大部分都在rt.jar下java.lang.reflect中,其实需要的类并不多,主要有以下几个:

  1. java.lang.Class 

Class类的实例表示正在运行的Java类和接口。

  1. java.lang.reflect.Field 

提供有关类或者接口的属性信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)属性或实例属性,简单的理解可以把它看成一个封装反射类的属性的类。有点绕,慢慢体会吧。

  1. java.lang.reflect.Constructor 

提供关于类的单个构造方法的信息以及对它的访问权限。这个类和Field类不同,Filed类封装类反射类的属性,而Constructor类则封装类反射类的构造方法。

  1. java.lang.reflect.Method 

提供关于类和接口上单个方法的信息。所反映的方法可能是类方法或者实例方法(包括抽象方法)。这个类不难理解,他的作用就是用来封装反射类方法的一个类。

  1. java.lang.reflect.Modifier 

提供了用于解码类和成员访问修饰符的静态方法和常量。修饰符集合被表示为具有表示不同修饰符的不同位位置的整数。

  1. java.lang.reflect.Array 

提供了动态创解决数组和访问数组的静态方法,该类中的所有方法都是静态方法。

反射的优缺点

 

优点

  • 可以在程序运行的过程中,操作这些对象。
  • 可以解耦,提高程序的可扩展性。

缺点

  • 因为是JVM操作,所以对于性能来说会有所下降。
  • 容易对程序源码造成一定的混乱。

探索 Class

 

java文件编译后变成class文件,class文件被类加载器加载到内存中,并且JVM根据其字节数组创建了对应的Class对象。

Class类是Java反射的起源,针对任何一个我们想使用的类,只有先为它产生一个Class对象,接下来就可以通过Class对象获取其他的信息。

JVM为每个类管理着一个独一无二的Class对象,当我们需要创建每个类的对象时,JVM会检查所要加载的类对应的Class对象是否已经存在。不存在,则JVM会根据类加载机制加载并创建对应的Class对象,最后使用Class对象创建出我们通常使用的实例对象。

获取Class类的三种方式

1.调用Object类的getClass()方法获得Class对象。

2.使用Class类的forName("com.tian.XXX")静态方法获取与字符串对应的对象(类或接口的全限定名)。

3.使用.class获取该类性的Class对象。

Class常用方法

 

方法非常之多。

获取类信息

了解了Java反射的详细细节之后,我们可以使用反射机制来获取类中的信息。

 

创建对象

使用无参构造方法创建对象

比如说下面这段代码:

  1. Class clazz = Class.forName("java.lang.String"); 
  2. String str = (String)clazz.newInstance(); 

这里需要注意,这个类必须是有无参构造方法,不然这种方式会报错的。

使用有参构造方法

可以使用三个步骤来完成:

1.获取指定类对应的Class对象

2.通过Class对象获取满足指定参数类型要求的构造方法类对象

3.调用指定的Constructor对应的newInstance方法,传入对应的参数值,创建出我们想要的实例对象。

  1. Class clazz = Class.forName("java.lang.String"); 
  2. Constructor constructor = clas.getConstructor(String.class); 
  3. String str = (String)constructor.newInstance("hello world"); 

这样就创建了一个String对象实例。

调用方法

前面已经聊过Method这个类,我们可以通过Method类中的invoke方法动态调用器方法。

  1. public final class Method extends Executable { 
  2.     public Object invoke(Object obj, Object... args){ 
  3.     //.... 
  4.     } 

这个方法的第一个参数是一个对象类型,表示要在指定的这个对象上调用这个方法(方法名称)。第二个参数是可变参数,用来给这个方法传递参数值;

invoke方法里返回的值用来表示动态调用指定方法后的返回值。如果调用私有的方法,先调用setAccessible(true)来曲线Java语言堆笨方法的访问检查,然后再调用invoke方法来真正执行这个私有方法。

访问成员变量的值

使用反射可以获取类的成员变量的对象代表,成员变量的对象代表是

java.lang.reflect.Field类的实例,可以使用他的getXyy()方法来获取指定对象上的值,也可以使用setXyy()方法来动态修改指定对象上的值,其中xyy是成员变量。

比如说:setAge(22);其中age就是成员变量。

操作数组

数组也是一个度一项,可以通过反射来查看数组的各个属性的信息,比如

  1. ingt [] intArr=new Int[10]; 
  2. Sysytem.out.prinlt("数组类型:"+intArr.getClass.getComponentType().getName()); 
  3.  
  4. Object obj=Array.newInstance(int.class, 10); 
  5. //维数组赋值 
  6. for(int i=0;i<10;i++){ 
  7.     Array.setInt(obj,i,i); 
  8. for(int i = 0;i<10;i++){ 
  9.     System.out.print("第"+i+"好元素为"+Array.getInt(obj,i)); 

反射与动态代理

代理模式是Java中使用频率相当高的设计模式之一,尤其是在牛逼的框架中,Spring,Mybatis,Dubbo等框架中。

其中反射就是一个很好的应用。

静态代理模式我们就没有必要提他了,相当于一个业务需要代理,你就得给他搞一个代理类。全是手动搞出来的。

动态代理的原理就是,在程序运行时候根据需要动态地创建目标类的代理对象,典型应用场景:

  • JDK动态代理
  • CGlib动态代理

关于动态代理,后面有专门的文章分析。

到此我们的反射相关的意见讲完了。具体还是建议自己下去手动敲敲代码,体会一下,便于更深刻的理解。

总结

 

面试被问到,建议回答以下几个方面的内容:

1.反射是什么

2.提供了什么功能

3.常用类有哪些

4.优缺点是什么

5.其他框架中国的应用(动态代理)

本文转载自微信公众号「Java后端技术全栈」,可以通过以下二维码关注。转载本文请联系Java后端技术全栈公众号。

 

责任编辑:武晓燕 来源: Java后端技术全栈
相关推荐

2024-03-14 14:56:22

反射Java数据库连接

2024-08-22 10:39:50

@Async注解代理

2024-03-05 10:33:39

AOPSpring编程

2024-09-20 08:36:43

零拷贝数据传输DMA

2024-03-22 06:56:24

零拷贝技术数据传输数据拷贝

2024-08-12 17:36:54

2024-08-29 16:30:27

2024-07-31 08:28:37

DMAIOMMap

2024-02-29 16:49:20

volatileJava并发编程

2024-03-01 11:33:31

2021-05-20 08:34:03

CDN原理网络

2024-06-04 09:02:03

2021-06-07 17:12:22

线程安全Atomic

2024-03-28 10:37:44

IoC依赖注入依赖查找

2023-12-27 18:16:39

MVCC隔离级别幻读

2024-11-19 15:13:02

2024-05-30 08:04:20

Netty核心组件架构

2024-03-06 15:38:06

Spring微服务架构扩展组件

2021-10-28 19:32:16

微信原理程序

2024-11-15 15:27:09

点赞
收藏

51CTO技术栈公众号