一、概述
了解 | 1.使用反射访问方法和属性 |
2.使用反射动态创建和访问数组 | |
理解 | 1.反射的概念和应用场合 |
2.使用反射获取类的信息 | |
3.使用反射创建对象 |
二、反射机制
1、反射的概念
在java中的反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。
好吧,这句话太正式了,我不是很理解,然后我在网上搜了哈,参考别人的理解,就是我们可以在java程序运行时加载、探知、使用编译期间完全未知的classes,
也就是能够看透class的能力,就是java的反射机制。实际上说白了,之前不是说private修饰的类成员,不能被类以外的类或对象访问吗,而反射就可以访问private修饰的类成员,也就是说利用java的反射机制,可以随便的访问类或对象的成员(不在乎它的访问级别)和它的构造方法。
2、java反射的三个动态性质
1) 运行时生成动态对象;
2) 运行期间调用方法;
3) 运行时更改属性。
3、java反射可以实现的功能
1) 在运行时判断任意一个对象所属的类;
2) 在运行时构造任意一个类的对象;
3) 在运行时判断任意一个类所具有的方法和属性;
4) 在运行时调用任意一个对象的方法;
5) 生成动态代理;(这个见动态代理)
4、java反射的应用场合
Java程序中许多对象在运行时都会出现两种类型:编译时类型和运行时类型,编译时的类型由声明该对象时使用的类型决定,运行时的类型由实际赋给该对象的类型决定,如:
此时p的编译时类型为Person,运行时类型为Student;因为对象p是引用类型,在编译时其类型由Person来确定,而在程序运行后发现p引用的内容实际是Student,因为只有在程序运行的时候才能知道p引用的内容改为了Student,所以称为运行时类型。
除此之外,程序在运行时还可能接收到外部传入的一个对象,该对象的编译时类型是Object,但程序又需要调用该对象运行时类型的方法。为了解决这些问题,程序需要在运行时发现对象和类的真实信息。然而,如果编译时根本无法预知该对象和类可能属于哪些类,程序只能依靠运行时信息来发现该对象和类的真实信息,此时就必须使用反射。
就是一句话,什么时候用反射,就是在编译的时候无法预知该对象和类可能属于哪些类,程序只能依靠运行时信息来发现该对象和类的真实信息。这时就需要使用反射。
5、java反射API介绍
Java中用于反射的相关类都是在java.lang.reflect包中
Class类 | 反射的核心类,可以获取类的属性、方法等内容信息 |
Field类 | 表示类的属性,可以获取和设置类中属性的值 |
Method类 | 表示类的方法,它可以用来获取类中方法的信息,或者执行方法。 |
Constructor类 | 表示类的构造方法 |
Array类 | Array类提供了动态创建和访问java数组的方法 |
5、使用反射机制的步骤
1) 获得想操作的类的java.lang.Class对象;
2) 调用Class的方法;
3) 使用反射API来操作这些信息;
7、获取Class对象的方式
我们已经知道,每个类被加载后,系统就会为该类生成一个对应的Class对象,通过该Class对象就可以访问到java虚拟机中的这个类。Java程序中获得Class对象通常有如下三种方式:
(1)调用某个对象的getClass()方法
(2)调用某个类的class属性来获取该类对应的Class对象
(3)使用Class类的forName()静态方法
注:(2)和(3)都是根据类来取得该类的Class对象,但相比之下,调用某个类的class属性来获取该类对应的Class对象这种方式有如下两种优势:
² 代码更安全,程序在编译阶段就可以检查需要访问的class对象是否存在;
² 程序性能更高,因为这种方式无需调用方法,所以程序的性能更好。
一般情况下,我们都选择.class来获取类,但如果我们只有一个表示类的全名的字符串,而我们不知道这个字符串的具体内容,此时,我们只能使用Class类的forName()方法来获取该字符串对应的Class对象。不过在使用Class类的forName()方法获取Class对象时,该方法可能会抛出一个ClassNotFoundException异常。
8、从Class类中获取信息
(1)访问Class对应的类所包含的构造方法
(2)访问Class对应的类所包含的方法
方法1
Method getMethod(String name,Class[] params)
返回此Class对象所表示的类的指定的public方法,name参数用于指定方法名称,params参数是按声明顺序标识该方法参数类型的Class对象的一个数组。
例:c.getMethod(“info”,String.class);
c.getMethod(“info”,String.class,Integer.class);
方法2
Method[] getMethods();
返回此Class对象所表示的类的所有public方法。
方法3
Method getDeclaredMethod(String name,Class[]params);
返回此Class对象所表示的类的指定的方法,与方法的访问级别无关。
方法4
Method[] getDeclaredMethods();
返回此Class对象所表示的类的全部方法,与方法的访问级别无关。
(3)访问Class对应的类所包含的属性
方法1
Field getField(String name);
返回此Class对象所表示的类的指定的public属性,name参数用于指定属性名称。
例:
c.getField(“age”);
方法2
Field[] getFields();
返回此Class对象所表示的类的所有public 属性。
方法3
Field getDeclaredField(String name);
返回此Class对象所表示的类的指定属性,与属性的访问级别无关。
Field[] getDeclaredFields();
返回此Class对象所表示的类的全部属性,与属性的访问级别无关。
(4)访问Class对应的类所包含的注释
<A extends Annotation>A getAnnotation(Class<A> annotationClass)
:试图获取该Class对象所表示类上指定类型的注释;如果该类型的注释不存在则返回null。其中annotationClass参数对应于注释类型的Class对象。
Annotation[] getAnnotations();返回此元素上存在的所有注释
Annotation[] getDeclaredAnnotations();返回直接存在于此元素上的所有注释。
(5)访问Class对应的类所包含的内部类
Class[] getDeclaredClasses();
返回该Class对象所对应类里包含的全部内部类
(6)访问Class对应的类所在的外部类
Class getDeclaringClass();
返回该Class对象所在的外部类
(7)访问该Class对象所对应类所继承的父类、所实现的接口等int getModifiers();——返回此类或接口的所有修饰符
Class[] getInterfaces();——返回该Class对象对应类所实现的全部接口
Package getPackage();——获取此类的包
String getName();——以字符串形式返回此Class对象所表示的类的名称
String getSimpleName();——以字符串形式返回此Class对象所表示的类的简
称
Class getSuperclass();——返回该Class所表示的类的超类对应的Class对象
9、创建对象
通过反射来生成对象,有如下两种方式
(1) 使用newInstance()创建对象
这种方式要求该Class对象的对应类有默认构造方法,而执行newInstance()方
法时实际上是利用默认构造方法来创建该类的实例。
(2) 使用Constructor对象创建对象
要先使用Class对象获取指定的Constructor对象,再调用Constructor对象的
newInstance()方法来创建该Class对象对应类的实例。通过这种方式可以选择
使用某个类的指定构造方法来创建实例。
反射技术多用于框架及基础平台中,例如Spring
如果我们不想利用默认构造方法来创建java对象,而想利用指定的构造方法来
创建Java对象,则需要利用Constructor对象了,每个Constructor对应一个
构造方法,利用指定构造方法来创建java对象需要三个步骤:
获取该类的Class对象;
利用Class对象的getConstructor()方法来获取指定构造方法;
调用Constructor的newInstance()方法来创建Java对象。
注:在java中,无论生成某个类的多少个对象,这些对象都会对应于同一个Class
对象,要想使用反射,首先需要获得待处理类或对象所对应的Class对象。