文章目录
Java_反射(Reflection)机制
-
通常情况下编写代码都是固定的,无论运行多少次执行的结果也是固定的,在某些特殊场合中编写代码时不确定要创建什么类型的对象,也不确定要调用什么样的方法,这些都希望通过运行时传递的参数来决定,该机制叫做动态编程技术,也就是反射机制。通俗来说,反射机制就是用于动态创建对象并且动态调用方法的机制。
-
Reflection(反射)
是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API
取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。 -
加载完类之后,在堆内存的方法区中就产生了一个
Class类
型的对象(一个类只有一个Class对象
),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。 -
主流的框架底层都是采用反射机制实现的
如: Person p = new Person(); - 表示声明Person类型的引用指向Person类型的对象 p.show(); - 表示调用Person类中的成员方法show
编译期和运行期
- 编译期:是指把源码交给编译器编译成计算机可以执行的文件的过程。在 Java 中也就是把 Java 代码编成
class
文件的过程。编译期只是做了一些翻译功能,并没有把代码放在内存中运行起来,而只是把代码当成文本进行操作,比如检查错误。 - 运行期:是把编译后的文件交给计算机执行,直到程序运行结束。所谓运行期就把在磁盘中的代码放到内存中执行起来。
动态语言和静态语言的区别
- 动态语言是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以 被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运 行时代码可以根据某些条件改变自身结构。
- 静态语言与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、C、 C++
- Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动 态性可以利用反射机制、字节码操作获得类似动态语言的特性。 Java的动态性让编程的时候更加灵活!
Java_Class类
基本概念
- java.lang.Class类的实例可以用于描述Java应用程序中的类和接口,也就是一种数据类型
- 该类没有公共构造方法,该类的实例由Java虚拟机和类加载器自动构造完成,本质上就是加载到内存中的运行时类。
获取Class对象的方式
- 使用数据类型.class的方式可以获取对应类型的Class对象。
- 使用引用/对象.getClass()的方式可以获取对应类型的Class对象。
- 使用包装类.TYPE的方式可以获取对应基本数据类型的Class对象。
- 使用Class.forName()的方式来获取参数指定类型的Class对象。
- 使用类加载器ClassLoader的方式获取指定类型的Class对象。
常用的方法
方法声明 | 功能 |
---|---|
static Class<?> forName(String className) | 用于获取参数指定类型对应的Class对象并返回 |
T newInstance() | 用于创建该Class对象所表示类的新实例 |
获取Class类的实例(三种方法)
-
Class clazz = String.class;
前提是已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高 -
Class clazz = “className”.getClass();
已知某个类的实例,调用该实例的getClass()
方法获取Class对象 -
Class clazz = Class.forName(“java.lang.String”);
已知一个类的全类名,且该类在类路径下,可通过Class类
的静态方法forName()
获取,可能抛出ClassNotFoundException
-
反射从程序的运行结果来看也很好理解,即:
可以通过对象反射求出类的名称。
在反射过后,可以得到某个类的属性、方法和构造器、某个类到底实现了哪些接口。 -
对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象,并且
Class 对象包含了特定某个(class/interface/enum/annotation/primitive type/void/[])
的有关信息。 -
Class本身也是一个类,并且只能
Class对象
由系统建立对象,一个加载类在JVM中只会有一个Class实例,即一个Class对象对对应一个加载到JVM中的一个.class
文件 -
每个类的实例都会记得自己是由哪个
Class
实例所生成的,而且通过Class
可以完整的得到一个类中的所有被加载的结构。Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象
Java_Constructor类
基本概念
- java.lang.reflect.Constructor类主要用于描述获取到的构造方法信息
Constructor类常用方法
方法 | 功能 |
---|---|
Constructor getConstructor(Class<?>… parameterTypes) | 用于获取此Class对象所表示类型中参数指定的公共构造方法 |
Constructor<?>[] getConstructors() | 用于获取此Class对象所表示类型中所有的公共构造方法 |
T newInstance(Object… initargs) | 使用此Constructor对象描述的构造方法来构造Class对象代表类型的新实例 |
int getModifiers() | 获取方法的访问修饰符 |
String getName() | 获取方法的名称 |
Class<?>[] getParameterTypes() | 获取方法所有参数的类型 |
Java_Field类
基本概念
- java.lang.reflect.Field类主要用于描述获取到的单个成员变量信息。
Class类的常用方法
方法 | 功能 |
---|---|
Field getDeclaredField(String name) | 用于获取此Class对象所表示类中参数指定的单个成员变量信息 |
Field[] getDeclaredFields() | 用于获取此Class对象所表示类中所有成员变量信息 |
Field类的常用方法
方法 | 功能 |
---|---|
Object get(Object obj) | 获取参数对象obj中此Field对象所表示成员变量的数值 |
void set(Object obj, Object value) | 将参数对象obj中此Field对象表示成员变量的数值修改为参数value的数值 |
void setAccessible(boolean flag) | 当实参传递true时,则反射对象在使用时应该取消 Java 语言访问检查 |
int getModifiers() | 获取成员变量的访问修饰符 |
Class<?> getType() | 获取成员变量的数据类型 |
String getName() | 获取成员变量的名称 |
Java_Method类
基本概念
- java.lang.reflect.Method类主要用于描述获取到的单个成员方法信息。
常用方法
方法 | 功能 |
---|---|
Method getMethod(String name,Class<?>… parameterTypes) | 用于获取该Class对象表示类中名字为name参数为parameterTypes的指定公共成员方法 |
Method[] getMethods() | 用于获取该Class对象表示类中所有公共成员方法 |
Object invoke(Object obj,Object… args) | 使用对象obj来调用此Method对象所表示的成员方法,实参传递args |
int getModifiers() | 获取方法的访问修饰符 |
Class<?> getReturnType() | 获取方法的返回值类型 |
String getName() | 获取方法的名称 |
Class<?>[] getParameterTypes() | 获取方法所有参数的类型 |
Class<?>[] getExceptionTypes() | 获取方法的异常信息 |
获取其它结构信息
方法声明 | 功能介绍 |
---|---|
Package getPackage() | 获取所在的包信息 |
Class<? super T> getSuperclass() | 获取继承的父类信息 |
Class<?>[] getInterfaces() | 获取实现的所有接口 |
Annotation[] getAnnotations() | 获取注解信息 |
Type[] getGenericInterfaces() | 获取泛型信息 |
Java_反射机制的功能位于Java.lang.reflect
包中
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时获取泛型信息
- 在运行时调用任意一个对象的成员变量和方法
- 在运行时处理注解
- 生成动态代理
通过反射要想直到一个类的属性和方法必须先获取到该类的字节码文件对象
获取类的信息时,使用的就是 Class
类中的方法。所以先要获取到每一个字节码文件(.class)
对应的 Class 类型
的对象.
返回同一个类型为 Class 的对象
Class labelCls = label1.getClass(); // label1为 JLabel 类的对象
Java_反射机制的优缺点
优点:
- 通过反射在运行时动态获取类的实例,提高系统的灵活性和扩展性
- 反射与Java的动态编译结合,提高代码灵活性
- Java 是先编译再运行的语言,反射能够让我们很方便的创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码的链接,更加容易实现面向对象。
缺点
- 反射会消耗一定的系统资源,因此,如果不是动态的创建一个对象,那么基本不需要使用反射
- 反射调用方法时可以忽略权限检查,获取这个类的私有方法和属性,因此可能会破坏类的封装性而导致安全问题
- Java反射机制很少使用