面试复习之—Java基础(十二):反射

最近在准备面试,把知识点复习一遍,整理出的笔记记录下,里面会穿插代码和面试例题。

内容不是原创,是总结和收集,并在理解的基础上进行一些完善,如果侵权了请联系作者,若有错误也请各位指正。因为收集的时候忘记把来源记录下来了,所以就不po出处了,请见谅(这是个坏习惯,一定改)。




这是面试复习内容的第十二篇——反射,主要是Java基础的内容,所有内容将分为几篇来写。

反射


反射的概念

反射(Reflection)是Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。

Oracle官方对反射的解释是:
Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.
The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.

简而言之,通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。

程序中一般的对象的类型都是在编译期就确定下来的,而Java反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。所以我们可以通过反射机制直接创建对象,即使这个对象的类型在编译期是未知的。

反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。

Java反射框架主要提供以下功能:
1.在 运行时 判断任意一个对象所属的类;
2.在 运行时 构造任意一个类的对象;
3.在 运行时 判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
4.在 运行时 调用任意一个对象的方法


反射的基础——Class类

关于Class类的内容可参考上一篇内容: Java基础(十一):Class类和Object类.

1、Class是一个类,一个描述类的类(也就是描述类本身),封装了描述方法的Method,描述字段的Filed,描述构造器的Constructor等属性。
2、对象照镜子后(反射)可以得到的信息:某个类的数据成员名、方法和构造器、某个类到底实现了哪些接口。
3、对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个Class对象包含了特定某个类的有关信息。
4、Class 对象只能由系统建立对象。
5、一个类在 JVM 中只会有一个Class实例。

总结归纳一下:

  • JDK有一个类叫做Class,这个类用来封装所有Java类型,包括这些类的所有信息,JVM中类信息是放在方法区的。
  • 所有类在加载后,JVM会为其在堆中创建一个Class<类名称>的对象,并且每个类只会有一个Class对象,这个类的所有对象都要通过Class<类名称>来进行实例化。
  • 上面说的是JVM进行实例化的原理,当然实际上在Java写代码时只需要用类名称就可以进行实例化了。

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

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象。

反射过程分析

分析反射过程的时候先说说几个概念:

  • 对象:内存上来说是分配在堆上面的一块内存区域
  • 类:把一类具体事物相同特征,功能/行为抽象为属性与方法过程。类是对象的模板,对象是类的具体表现。
  • 构造函数:与类名同名的函数,用来实例化对象并初始化成员变量。注意:构造器、构造函数不能称为构造方法。

类的结构:

  • 静态块:当对应的class文件被首次加载到虚拟机时执行。
  • 代码块
  • 构造函数

静态属性与变量首先加载。其次时静态块,之后是代码块,最后是构造函数。

类的实例化过程

  • 当一个类被创建(A a=new A();),并且这个类是首次被加载时,会在堆中开辟出一块内存存放类的class文件。之后会在堆中开辟一块内存当做对象空间,存储这个类并且将这个类的非静态的成员变量拷贝过来(静态成员不拷贝,所有实例共享),并持有对应的方法区的方法的句柄,这块内存有一个唯一内存地址,栈中的a对象指向的就是这个内存地址。
  • 之后再次实例化(new)A类,此时内存中已经有一个A类的class,所以不会在创建一个A.class,但是此时会在堆中开辟一块新的空间并且将这个类的非静态成员拷贝并持有对应的方法区类的方法的句柄,这块内存空间标注一个新的内存地址。
  • 而反射就是把java类中的各种成分映射成一个个的Java对象。

类的实例化过程及反射过程图解
类的实例化过程及反射过程

反射的作用

Java中编译类型有两种:
静态编译:在编译时确定类型,绑定对象即通过。
动态编译:运行时确定类型,绑定对象。
方法重载(overload) 实现的是编译时的多态性(也称为前绑定)。
方法重写(override) 实现的是运行时的多态性(也称为后绑定)。

动态编译最大限度地发挥了Java的灵活性,体现了多态的应用,可以减低类之间的耦合性。 Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public、static等)、superclass(例如Object)、实现中的interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。

反射(reflection)可以在运行时加载、探知、使用编译期间完全未知的classes。即Java程序可以加载一个运行时才得知名称的class,获取其完整构造,并生成其对象实体、或对其fields设值、或唤起其methods。

反射(reflection)允许静态语言在运行时(runtime)检查、修改程序的结构与行为。 在静态语言中,使用一个变量时,必须知道它的类型。在Java中,变量的类型信息在编译时都保存到了class文件中,这样在运行时才能保证准确无误;换句话说,程序在运行时的行为都是固定的。如果想在运行时改变,就需要反射这东西了。

实现Java反射机制的类都位于java.lang.reflect包中:

  • Class类:代表一个类
  • Field类:代表类的成员变量(类的属性)
  • Method类:代表类的方法
  • Constructor类:代表类的构造方法
  • Array类:提供了动态创建数组,以及访问数组的元素的静态方法。

一句话概括就是使用反射可以赋予jvm动态编译的能力,否则类的元数据信息只能用静态编译的方式实现,例如热加载,Tomcat的classloader等等都没法支持。

很多人都认为反射在实际的Java开发应用中并不广泛,其实不然。

当我们在使用IDE(如Eclipse,IDEA)时,当我们输入一个对象或类并想调用它的属性或方法时,一按点号,编译器就会自动列出它的属性或方法,这里就会用到反射。
反射最重要的用途就是开发各种通用框架。

很多框架(比如Spring)都是配置化的(比如通过XML文件配置JavaBean,Action之类的),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射——运行时动态加载需要加载的对象。

举一个例子,在运用Struts 2框架的开发中我们一般会在struts.xml里去配置Action,比如:

<action name="login" class="org.test.action.LoginAction"
               method="execute">
	<result>/index.jsp</result>
    <result name="error">login.jsp</result>
</action>

配置文件与Action建立了一种映射关系,当View层发出请求时,请求会被StrutsPrepareAndExecuteFilter拦截,然后Stru

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值