Java 反射 理解

Java 反射

定义

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。

简而言之,反射机制可以获取任意一个类的字节码,并通过这个字节码文件创建出类对象,访问该对象。

关键词:任意,可见Java的反射机制是非常灵活的,在spring框架中得到了充分的应用 - 配置文件和类的自动装配,即 IOC 机制。

如何反射?

要使用反射机制反射出一个类,那么必须先获得类的字节码文件对象,即 .class。

如何获取类的字节码文件?有几种方式?

  1. 调用某个类的对象实例的 getClass() 方法获取

    Cat cat = new Cat();
    Class c = cat.getClass();
    
  2. 直接调用类的 .class 属性

    Class c = Cat.class();
    
  3. 使用 Class 的 forName(String className) 方法,通过类的全路径名

    Class c = Class.forName("reflect.Cat");
    reflect.CatCat 类的全路径名
    

由于第三种方式不需要事先创建类,或者获取类,所以更灵活。 Spring 就是用这样的方式进行组件的创建,根据配置文件和反射机制和IOC创建、获取、装配组件。

使用场景

1、通过反射机制破坏单例模式

单例模式中,类的构造方法都是设置为 private 的,所以使用常规的 new 是无法创建对象的。但是,反射机制可以。

做法:我们可以先获取类的字节码文件,然后通过字节码文件获取类的构造器,将构造器可访问权限设置为 true,调用构造器的 newInstance() 获取一个对象实例。

class Cat {
    String name;
    private Cat() {}
}

public class ReflectTest {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, ClassNotFoundException {
        Class<Cat> catClass = Cat.class;
        Constructor<Cat> cata = catClass.getDeclaredConstructor();
        cata.setAccessible(true);
        Cat cat1 = cata.newInstance();
        Cat cat2 = Cat.getCat();
        System.out.println(cat1);
        System.out.println(cat2);
    }
}

输出:

Java 反射 理解_第1张图片

得到两个不同的对象!

2、Spring的IOC机制中的应用

Spring 是如何帮我们创建对象,并放到容器中?IOC 机制

实际上 IOC机制实际上就是使用了反射机制来实现的。

我们看下,下面的伪代码实现过程:

//解析元素的id属性得到该字符串值为"sqlSessionFactory" 
String idStr = "sqlSessionFactory";  
//解析元素的class属性得到该字符串值为"org.mybatis.spring.SqlSessionFactoryBean"  
String classStr = "org.mybatis.spring.SqlSessionFactoryBean";  
//利用反射知识,通过classStr获取Class类对象  
Class cls = Class.forName(classStr);  
//实例化对象  
Object obj = cls.newInstance();  
//container表示Spring容器  
container.put(idStr, obj);  

//当一个类里面需要用另一类的对象时,我们继续下面的操作

//解析元素的name属性得到该字符串值为“dataSource”  
String nameStr = "dataSource";  
//解析元素的ref属性得到该字符串值为“dataSource”  
String refStr = "dataSource";  
//生成将要调用setter方法名  
String setterName = "set" + nameStr.substring(0, 1).toUpperCase() 						+ nameStr.substring(1);  
//获取spring容器中名为refStr的Bean,该Bean将会作为传入参数  
Object paramBean = container.get(refStr);  
//获取setter方法的Method类,此处的cls是刚才反射代码得到的Class对象  
Method setter = cls.getMethod(setterName, paramBean.getClass());  
//调用invoke()方法,此处的obj是刚才反射代码得到的Object对象  
setter.invoke(obj, paramBean);  

是不是很熟悉,虽然是伪代码,但是和我们本篇讲的反射机制的使用是相同的,现在知道我们的反射机制用在哪了吧,没错就是我们经常提到的Java web框架中,里面就用到了反射机制,只要在代码或配置文件中看到类的完全限定名(包名+类名),即完整路径名,其底层原理基本上使用的就是Java的反射机制。

ref:

  1. https://blog.csdn.net/Appleyk/article/details/77879073
  2. https://codeantenna.com/a/USAuldhCFd

你可能感兴趣的:(java,java)