IoC的底层实现技术是反射技术,目前Java、C#、PHP 等语言均支持反射技术。
在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法;对任意一个对象,都能够调用它的任意方法和属性(包括私有的方法和属性)。这种动态获取信息以及动态调用对象对象和对象方法的功能就被称作反射机制。
通俗来讲,反射技术就是根据给出的类名(字符串方式)来动态生成对象。这种编程方式可以在生成对象时再决定到底生成哪一种对象。反射的应用是很广泛的,很多成熟的框架都离不开反射技术,比如Java中的Hibernate、Spring框架。
反射技术很早就出现了,初期的反射编程速度相对于传统对象生成速度至少要慢10倍,目前的反射技术经过优化,反射方式生成对象和传统对象生成方式的速度相差不大,大约有1~2被的差距。由于IoC容器通过反射方式生成对象时,在运行效率上有一定的损耗,因此,如果系统追求运行效率,就必须权衡是否使用反射技术。
在Java语言中,可以通过Class类的forName()方法获取类的信息,同Class类的newInstance()方法获得一个具体的实例。在java.lang.reflect包里,Java语言提供了Field、Method、Modifier、Constructor、InvocationHandler等类,可以轻松实现反射技术。
为了让大家了解依赖注入的基础,示例展示了使用Java实现的一个反射应用:通过Class类来实现类的定义,通过Field来获取类的属性,通过Method类来获取方法,并通过invoke来调用方法,设置类的某个属性。
首先我们创建一个InnerPerson类,InnerPerson类的代码如下
class InnerPerson {
private String name;
private int age;
public String pub;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "reflect.InnerPerson{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
};
然后我们创建一个ReflectDemo01类,在该类中我们使用三种方式来实现类的实例化。ReflectDemo1的代码如下图所示
public class ReflectDemo01 {
public static void main(String[] args) {
//三种不同类实例化方法
//第一种实例
Class<?> firstInstance = null;
//第二种实例
Class<?> secondInstance = null;
//第三种实例
Class<?> thirdInstance = null;
//通过类名实例化的方法
try {
firstInstance = Class.forName("com.example.servlet001.InnerPerson");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//通过Object类中的方法实例化
secondInstance=new InnerPerson().getClass();
//通过类.class实例化
thirdInstance=InnerPerson.class;
System.out.println("类名称:"+firstInstance.getName());
System.out.println("类名称:"+secondInstance.getName());
System.out.println("类名称:"+thirdInstance.getName());
}
}
运行该程序后得到的结果如下图所示
继续修改ReflectDemo01 的代码,代码内容如下
public class ReflectDemo01 {
public static void main(String[] args) {
//三种不同类实例化方法
//第一种实例
Class<?> firstInstance = null;
//第二种实例
Class<?> secondInstance = null;
//第三种实例
Class<?> thirdInstance = null;
//通过类名实例化的方法
try {
firstInstance = Class.forName("com.example.servlet001.InnerPerson");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//通过Object类中的方法实例化
secondInstance = new InnerPerson().getClass();
//通过类.class实例化
thirdInstance = InnerPerson.class;
// System.out.println("类名称:"+firstInstance.getName());
// System.out.println("类名称:"+secondInstance.getName());
// System.out.println("类名称:"+thirdInstance.getName());
//获取类实例中的字段并输出
//获得public的所有字段数组
Field[] fields = firstInstance.getFields();
//获取任何权限的所有字段
Field[] allFields = firstInstance.getDeclaredFields();
System.out.println("---------------所有public字段----------------");
for (Field fx : fields) {
System.out.println(fx);
}
System.out.println("---------------所有字段----------------");
for (Field fx : allFields) {
System.out.println(fx);
}
//获取方法并输出
Method[] m1 = firstInstance.getMethods();
Method[] m2 = firstInstance.getDeclaredMethods();
System.out.println("---------------所有public方法----------------");
for (Method method : m1) {
System.out.println(method);
}
System.out.println("---------------所有方法----------------");
for (Method method : m2) {
System.out.println(method);
}
//执行方法并输出
System.out.println("---------------使用invoke执行方法----------------");
//反射式的,只需要写入方法名,不需要加括号
Method m = null;
try {
Object o = firstInstance.newInstance();
try {
m = firstInstance.getDeclaredMethod("setName", String.class);
try {
m.invoke(o, new Object[]{"John"});
System.out.println("当前对象为:" + o);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
完整的代码如下所示
package com.example.servlet001;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectDemo01 {
public static void main(String[] args) {
//三种不同类实例化方法
//第一种实例
Class<?> firstInstance = null;
//第二种实例
Class<?> secondInstance = null;
//第三种实例
Class<?> thirdInstance = null;
//通过类名实例化的方法
try {
firstInstance = Class.forName("com.example.servlet001.InnerPerson");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//通过Object类中的方法实例化
secondInstance = new InnerPerson().getClass();
//通过类.class实例化
thirdInstance = InnerPerson.class;
// System.out.println("类名称:"+firstInstance.getName());
// System.out.println("类名称:"+secondInstance.getName());
// System.out.println("类名称:"+thirdInstance.getName());
//获取类实例中的字段并输出
//获得public的所有字段数组
Field[] fields = firstInstance.getFields();
//获取任何权限的所有字段
Field[] allFields = firstInstance.getDeclaredFields();
System.out.println("---------------所有public字段----------------");
for (Field fx : fields) {
System.out.println(fx);
}
System.out.println("---------------所有字段----------------");
for (Field fx : allFields) {
System.out.println(fx);
}
//获取方法并输出
Method[] m1 = firstInstance.getMethods();
Method[] m2 = firstInstance.getDeclaredMethods();
System.out.println("---------------所有public方法----------------");
for (Method method : m1) {
System.out.println(method);
}
System.out.println("---------------所有方法----------------");
for (Method method : m2) {
System.out.println(method);
}
//执行方法并输出
System.out.println("---------------使用invoke执行方法----------------");
//反射式的,只需要写入方法名,不需要加括号
Method m = null;
try {
Object o = firstInstance.newInstance();
try {
m = firstInstance.getDeclaredMethod("setName", String.class);
try {
m.invoke(o, new Object[]{"John"});
System.out.println("当前对象为:" + o);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
class InnerPerson {
private String name;
private int age;
public String pub;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "reflect.InnerPerson{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
};
运行该示例后的输出如下图所示