概念
对于反射,官方给出的概念:反射是Java语言的一个特性,它允许程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。说的简单点,程序在运行时动态获取类的属性和方法并调用对象称为反射,反之则是在代码中固定调用的是哪一个对象,哪一个方法。
优缺点
优点:可以实现动态创建对象和编译,体现出很大的灵活性。让用户在不需要修改代码的情况下获得新增的类的对象。
缺点:性能会影响。
Spring的IOC如何使用反射
我们都知道Spring是通过反射和工厂模式实现的IOC容器,那么为什么要用到反射? 先来看下不使用反射的工厂模式:
// 定义接口
interface fruit{
public abstract void eat();
}
// 接口实现类Apple和Orange
class Apple implements fruit{
public void eat(){
System.out.println("Apple");
}
}
class Orange implements fruit{
public void eat(){
System.out.println("Orange");
}
}
// 工厂类
class Factory{
public static fruit getInstance(String fruitName){
fruit f=null;
if("Apple".equals(fruitName)){
f=new Apple();
}
if("Orange".equals(fruitName)){
f=new Orange();
}
return f;
}
}
// 运行
public class hello{
public static void main(String[] a){
fruit f=Factory.getInstance("Orange");
f.eat();
}
}
很明显,上面写法的缺点是当我们再添加一个子类的时候,就需要修改工厂类。如果我们添加太多的子类,改动就会很多。下面用反射机制实现工厂模式:
// 定义接口
interface fruit{
public abstract void eat();
}
// 接口实现类Apple和Orange
class Apple implements fruit{
public void eat(){
System.out.println("Apple");
}
}
class Orange implements fruit{
public void eat(){
System.out.println("Orange");
}
}
// 工厂类
class Factory{
public static fruit getInstance(String ClassName){
fruit f=null;
try{
f=(fruit)Class.forName(ClassName).newInstance();
}catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
// 运行
class hello{
public static void main(String[] a){
// 运行的时候才知道我需要获得的是Apple实例对象
fruit f=Factory.getInstance("Reflect.Apple");
if(f!=null){
f.eat();
}
}
}
使用了反射后,就算我们需要添加任意多个子类,工厂类都不需要修改。使用反射机制实现的工厂模式可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。
IOC的粗略解析
IOC中最基本的技术就是“反射(Reflection)”编程,通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象,这种编程方式可以让对象在生成时才被决定到底是哪一种对象。只是在Spring中要生产的对象都在配置文件中给出定义,目的就是提高灵活性和可维护性。
我们可以把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言提供的反射机制,根据配置文件中给出的类名生成相应的对象。从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。