概念:
动态语言:是指程序在运行的过程中可以改变其结构(添加新的方法和属性)的语言。动态语言有JavaScript、Ruby、Python。C和C++不属于动态语言。从反射的角度来说Java属于半动态语言。
反射的思想是当我们的程序在运行时,需要动态地加载一些类 而这些类 可能之前用不到 所以没有被加载到 JVM ,所以在 运行时 需要动态的加载(比如数据库动态加载驱动类)。动态的加载的时 我们指定的类,并且获取该类中的所有内容。而且是一个将字节码文件中的内容封装成对象。那么好比将.class文件封装成.java文件(反编译的过程)。通过反射机制我们可以动态的获取、访问到java对象的属性,方法,构造函数等。
补充:
- 我们知道所有的Java类都继承一个Object类。Object类是类层次结构的根类。每个类都使用Object作为超类。所有的对象、数组都会实现这个类的方法。Object中的getClass():会返回一个Class对象(类对象)。
- Class对象实在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的。
- 静态编译:在编译时确定类型,绑定对象,即通过。
- 动态编译:在运行时确定类型,绑定对象。动态编译最大限度发挥了Java的灵活性,体现了多态的应用,减低了 类之间的耦合性。
反射机制的有缺点:
优点:可以实现动态地创建对象和编译,体现了很大的灵活性,提高程序的扩展性。
缺点:对性能有影响,使用反射基本上是一种解析操作,我可以告诉JVM,我们希望做什么并且它可以满足我们的要求,但是这些操作总是慢于直接执行的相同操作。
Java中关于反射的操作定义在:java.lang.reflect 包下
基本步骤:
- 获得Class对象,就是获取到指定名称的字节码文件对象。
- 实例化对象,获得类的属性、方法、构造函数。
- 访问属性、调用方法、调用构造函数创建对象。
获取Class对象:
在反射机制中获取class对象有三种方法
- 通过对象的getClass()方法获取。(缺点:先要创建该类的对象)。
- 通过数据类型的静态属性class(缺点:必须先明确该类)。
- 使用class类中的静态forName()方法。(优点:指定什么类名,就获取什么类的字节码文件对象,扩展性强)
package dong.test;
/**
* 获得类对象的三种方法
* @author YIMA
*
*/
public class Reflection {
public static void main(String[] args) throws ClassNotFoundException {
//方法1:通过对象reflection调用getClass()方法获得类对象
Reflection reflection = new Reflection();
Class class1 = reflection.getClass();
//方法2:通过静态属性class获得类对象
Class class2 = Reflection.class;
//方法3:调用类中的静态方法forName(),获取类对象。这里 的“dong.test.Reflection”意思是:dong.test包下的Reflection类。
Class class3 = Class.forName("dong.test.Reflection");
}
}
创建类的对象:
对象进行实例化时的初始化的方式有两种
-
调用无参的构造函数:调用newInstance()方法;(一般情况下,被反射的类,内部通常都会提供一个公有的空参数的构造函数)
-
调用带参的构造函数:先要获取指定参数列表的构造函数对象,然后通过该构造函数对象的newInstance(实际参数)进行对象的初始化;(注意:这里必须先明确具体的构造函数的参数类型,不便于扩展)
package dong.test;
import java.lang.reflect.Constructor;
/**
* 实例化类的对象
* @author YIMA
*
*/
public class Reflection {
private String r1;
public Reflection(String r1){
System.out.println("调用有参的构造函数");
this.r1 = r1;
}
public Reflection(){
System.out.println("调用无参的构造函数");
}
public static void main(String[] args) {
Class class3;
Object object;
Object object2;
try {
//方法3:调用类中的静态方法forName(),获取类对象
class3 = Class.forName("dong.test.Reflection");
//类对象通过无参newInstance()方法获取实例化一个对象
object = class3.newInstance();//调用了该类无参的构造函数
Constructor constructor = class3.getConstructor(String.class);//获取特定的构造函数
object2 = constructor.newInstance("test");//调用了该类有参的构造函数
} catch (Exception e) {
e.printStackTrace();
}
}
}
上面代码运行的结果:
调用无参的构造函数
调用有参的构造函数
获得类的构造函数
类型 | 方法 | 解释 |
---|---|---|
Constructor | getConstructor(Class[] patams) | 获得使用特殊参数的公共构造函数 |
Constructor[] | getConstructors() | 获得类中所有的公共构造函数 |
Constructor | getDeclaredConstructor(Class patams) | 获得所有的构造函数包括私有的 |
Constructor[] | getDeclaredConstructor() | 获得该类所有的构造函数包括私有的 |
package dong.test;
import java.lang.reflect.Constructor;
/**
* 获得构造函数
* @author YIMA
*
*/
public class Reflection{
private String r1;
public Reflection(String r1){
System.out.println("调用有参的构造函数");
this.r1 = r1;
}
public Reflection(){
System.out.println("调用无参的构造函数");
}
private Reflection(int i){}
public static void main(String[] args) {
Class class3 = null;
Constructor[] constructors = null;
try {
//方法3:调用类中的静态方法forName(),获取类对象
class3 = Class.forName("dong.test.Reflection");
//constructors = class3.getConstructors();//获取的是该类以及父类中的公有的构造函数
constructors = class3.getDeclaredConstructors();//获取本类的构造函数,包括私有的
} catch (Exception e) {
e.printStackTrace();
}
//遍历输出
for(Constructor con:constructors){
System.out.println(con);
}
}
}
运行结果:
private dong.test.Reflection(int)
public dong.test.Reflection()
public dong.test.Reflection(java.lang.String)
当上面的代码中执行的代码片段是:
constructors = class3.getConstructors();//获取的是该类以及父类中的公有的构造函数
此时的运行结果是:
public dong.test.Reflection()
public dong.test.Reflection(java.lang.String)
获取类的方法
package dong.test;
import java.lang.reflect.Method;
/**
* 获得方法
* @author YIMA
*
*/
public class Reflection{
private String r1;
public String getR1() {
return r1;
}
public void setR1(String r1) {
this.r1 = r1;
}
public void show(){
}
public static void main(String[] args) {
Class class3 = null;
Method[] methods = null;
try {
//方法3:调用类中的静态方法forName(),获取类对象
class3 = Class.forName("dong.test.Reflection");
//获取本类中的所有方法
methods = class3.getDeclaredMethods();
} catch (Exception e) {
e.printStackTrace();
}
for(Method m:methods){
System.out.println(m);
}
}
}
运行结果:控制输出了本类中的四个方法,其中也包括了main方法。
public static void dong.test.Reflection.main(java.lang.String[])
public java.lang.String dong.test.Reflection.getR1()
public void dong.test.Reflection.setR1(java.lang.String)
public void dong.test.Reflection.show()
获取类中指定的方法
补充:方法调用:invoke()
package dong.test;
import java.lang.reflect.Method;
/**
* 获得方法
* @author YIMA
*
*/
public class Reflection{
private String r1;
public String getR1() {
return r1;
}
public void setR1(String r1) {
System.out.println(r1);
this.r1 = r1;
}
public void show(){
}
public static void main(String[] args) {
Class class3 = null;
Method[] methods = null;
try {
//方法3:调用类中的静态方法forName(),获取类对象
class3 = Class.forName("dong.test.Reflection");
Object object = class3.newInstance();
//获取指定名称的方法
Method m = class3.getDeclaredMethod("setR1",String.class);
m.invoke(object, "获取指定名称的方法");
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果:
获取指定名称的方法