重拾Java反射(为什么?)

原创
2019/06/07 18:03
阅读数 29


前言:如标题所述,为什么要重拾Java反射?究其缘由,在Java中反射具有举足轻重的地位,一直以来都是Java中的闪亮点,并且反射是一系列出众的web框架设计的灵魂所在。PS:本文主要是理论,篇幅稍长,耐心阅读!



什么是Java反射

P 1

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


在Java JDK中,有Class类与java.lang.reflect类库一起对反射技术提供了全力的支持。


其实我们可以更加通俗的理解反射,即为我们可能每天都会做的一件事,那就是"照镜子";在镜子中我们可以看到一个完全的自己,类似的在镜子中我们也可以看到一个完整的类信息或完整的对象信息。


更进一步理解:Java反射就是把Java类中的各个组成部分映射成一个个具体的Java对象实例;eg:一个Java类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖组装,把各个组成部分映射组装成一个个实例对象。


其实:一个普通的类(程序编译后的 .class二进制类文件)中这些包括成员变量、方法、构造方法等在加入到Java程序运行时类中都有一个特殊的类(Class类)来描述。所以想要通过反射获得类实例(对象)是有前提的!



使用前提条件

P 2

前面我们了解了反射后还是不够的,接着来看看它的使用前提:就是必须先得到代表不同字节码文件的Class类,Class类用于表示.class文件(字节码)。也就是说:想要反射解剖出一个Java类,必须先要获取到该类的字节码文件对象,即Class类实例对象。而反射解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。


其实,反射的精髓就在于Class类型的对象。到这里我们不妨先回顾下"类加载过程",如下图:


具体分析:(以加载Employee类为例),如下图:

Class对象的由来是将class文件读入内存,并为之创建一个Class对象。其中这个Class对象很特殊。下面我们深入了解一下这个Class类



Class类的理解

P 3

1、由前面介绍可知,Java对象照镜子(反射)后可以得到的信息:某个Java类的成员属性、方法和构造器、某个Java类到底实现了哪些接口。对于每个具体Java类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个Java类的相关信息。

2、Class 对象是系统创建的对象。

3、一个具体Java类在 JVM 中只会有一个Class类实例。

4、每个具体Java类的实例都会记得自己是由哪个 Class 类实例所生成


简单了解Class类后我们在深入一下:

先来了解一个概念,RTTI(Run-Time Type Identification)运行时类型识别,对于这个词一直是 C++ 中的概念,至于Java中出现RRTI的说法则是源于《Thinking in Java》一书,其作用是在运行时识别一个对象的类型和类的信息这里分两种:


一种是传统的”RRTI”,它假定我们在编译期已知道了所有类型(在没有反射机制创建和使用类对象时,一般都是编译期已确定其类型,如new对象时该类必须已定义好)。


另外一种”RRTI”是反射机制,就是今天的主题,它允许我们在运行时发现和使用类型的信息。在Java中用来表示运行时类型信息的对应类就是Class类,Class类也是一个实实在在的类,存在于JDK的java.lang包中,其部分源码如下:

public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement
{
private static final int ANNOTATION= 0x00002000;
private static final int ENUM = 0x00004000;
private static final int SYNTHETIC = 0x00001000;

private static native void registerNatives();
static {
registerNatives();
}
。。。
//小写class表示是一个类类型,大写Class表示这个类的名称


这里我们可以得出关于Class类的几点知识总结:

  1. Class类也是类的一种,与class关键字是不一样的。    

  2. 手动编写的类被编译后会产生一个Class对象,其表示的是创建的类的类型信息,而且这个Class对象保存在同名.class的文件中(字节码文件),比如创建一个Student类,编译StudentStudent类后就会创建其包含类相关类型信息的Class对象,并保存在Student.class字节码文件中。

  3. 每个通过关键字class标识的类,在内存中有且只有一个与之对应的Class对象来描述其类型信息,无论创建多少个实例对象,其依据的都是用一个Class对象。

  4. Class类只存私有构造函数,因此对应Class对象只能有JVM创建和加载。

  5. Class类的对象作用是运行时提供或获得某个对象的类型信息,这点对于反射技术很重要。


获取Class对象的三种方式:

1.通过类名获取 类名.class

任何数据类型(包括基本数据类型)都有一个“静态”的class属性

2.通过对象获取 对象名.getClass()
Object ——> getClass();

3.通过全类名获取 Class.forName(全类名)
通过Class类的静态方法:forName(String className)(常用)


三种方式常用第三种,第一种需要导入类的包,依赖太强,不导包就抛编译错误。第二种对象都有了还要反射干什么。一般都用第三种,一个字符串可以传入也可写在配置文件中等多种方法。


举例如下:

@Test
public void testClass() throws ClassNotFoundException {
Class clazz = null;

//1.通过类名
clazz = Person.class;

//2.通过对象名
//这种方式是用在传进来一个对象,却不知道对象类型的时候使用
Person person = new Person();
clazz = person.getClass();
//上面这个例子的意义不大,因为已经知道person类型是Person类,再这样写就没有必要了
//如果传进来是一个Object类,这种做法就是应该的
Object obj = new Person();
clazz = obj.getClass();

//3.通过全类名(会抛出异常)
//一般框架开发中这种用的比较多,因为配置文件中一般配的都是全类名,通过这种方式可以得到Class实例
String className=" com.atguigu.java.fanshe.Person";
clazz = Class.forName(className);

//字符串的例子
clazz = String.class;
clazz = "javaTest".getClass();
clazz = Class.forName("java.lang.String");
}


Class类的常用方法:

方法名

功能说明

static Class forName(String name)

返回指定类名 name 的 Class 对象

Object newInstance()

调用缺省构造函数,返回该Class对象的一个实例

Object newInstance(Object []args)

调用当前格式构造函数,返回该Class对象的一个实例

getName()

返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称

Class getSuperClass()

返回当前Class对象的父类的Class对象

Class [] getInterfaces()

获取当前Class对象的接口

ClassLoader getClassLoader()

返回该类的类加载器

Class getSuperclass()

返回表示此Class所表示的实体的超类的Class


这里我们说明一下newInstance()方法:

public void testNewInstance() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
//1.获取Class对象
String className="com.atguigu.java.fanshe.Person";
Class clazz = Class.forName(className);

//利用Class对象的newInstance方法创建一个类的实例
Object obj = clazz.newInstance();
System.out.println(obj);
}
//结果是:com.atguigu.java.fanshe.Person@2866bb78


可以看出确实是创建了一个Person实例,但是Person类有两个构造方法,到底是调用的哪一个构造方法呢?


实际调用的是类的无参数的构造器。所以在我们在定义一个类的时候,定义一个有参数的构造器,作用是对属性进行初始化,还要写一个无参数的构造器,作用就是反射时候用。


这就是为什么一般地、一个类若声明一个带参的构造器,同时要声明一个无参数的构造器的缘由!



Class 类的实例表示正在运行的 Java 应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型)


Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。


方法共有64个太多了,更多方法,可以参考官方API



反射技术

P 4

Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的內部信息,并能直接操作任意对象的内部属性及方法。


Java反射机制主要提供了以下功能:

  • 在运行时构造任意一个类的对象

  • 在运行时获取任意一个类所具有的成员变量和方法

  • 在运行时调用任意一个对象的方法(属性)

  • 生成动态代理


在Java中,Class类与java.lang.reflect类库一起对反射技术进行了全力的支持。在反射包中,我们常用的类主要有Constructor类表示的是Class 对象所表示的类的构造方法,利用它可以在运行时动态创建对象、Field表示Class对象所表示的类的成员变量,通过它可以在运行时动态修改成员变量的属性值(包含private)、Method表示Class对象所表示的类的成员方法,通过它可以动态调用对象的方法(包含private)。


反射核心点:

 1. Class: 是一个类; 一个描述类的类.

封装了

描述方法的 Method,

描述字段的 Filed,

描述构造器的 Constructor 等属性.

 2. 如何得到 Class 对象:

2.1 Person.class

2.2 person.getClass()

2.3 Class.forName("com.atguigu.javase.Person")

3. 关于 Method:

3.1 如何获取 Method:

1). getDeclaredMethods: 得到 Method 的数组.

2). getDeclaredMethod(String methondName, Class ... parameterTypes)

3.2 如何调用 Method

1). 如果方法时 private 修饰的, 需要先调用 Method 的 setAccessible(true), 使其变为可访问

2). method.invoke(obj, Object ... args);

4. 关于 Field:

4.1 如何获取 Field: getField(String fieldName)

4.2 如何获取 Field 的值: 

1). setAccessible(true)

2). field.get(Object obj)

4.3 如何设置 Field 的值:

field.set(Obejct obj, Object val)

5. 了解 Constructor 和 Annotation 

6. 反射和泛型.

6.1 getGenericSuperClass: 获取带泛型参数的父类, 返回值为: BaseDao<Employee, String>

6.2 Type 的子接口: ParameterizedType

6.3 可以调用 ParameterizedType 的 Type[] getActualTypeArguments() 获取泛型参数的数组.


本文到此结束!!!


参考文章:

https://www.cnblogs.com/tech-bird/p/3525336.html

https://blog.csdn.net/javazejian/article/details/70768369

https://blog.csdn.net/sinat_38259539/article/details/71799078






·end·

—如果喜欢,快分享给你的朋友们吧—



有任何问题、意见等 请在公众号内留言


本文分享自微信公众号 - 一只蓝色猿(umizhang0910)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
在线直播报名
返回顶部
顶部