反射、工厂模式、IOC容器浅尝 一篇入门

反射

什么是反射?

个人目前理解:反射是在程序运行期间获取class信息,用这些信息做一些操作,例如本文后续要用的实例化一个对象以及为属性赋值。

如何获取class信息

  1. 调用对象的getClass方法
  2. 调用类的class属性
  3. 使用Class类中的forName()静态方法(最安全,性能最好)即:Class.forName(“类的全路径”)

常用方法

//获取包名、类名
clazz.getPackage().getName()//包名
clazz.getSimpleName()//类名
clazz.getName()//完整类名
 
//获取成员变量定义信息
getFields()//获取所有公开的成员变量,包括继承变量
getDeclaredFields()//获取本类定义的成员变量,包括私有,但不包括继承的变量
getField(变量名)
getDeclaredField(变量名)
 
//获取构造方法定义信息
getConstructor(参数类型列表)//获取公开的构造方法
getConstructors()//获取所有的公开的构造方法
getDeclaredConstructors()//获取所有的构造方法,包括私有
getDeclaredConstructor(int.class,String.class)
 
//获取方法定义信息
getMethods()//获取所有可见的方法,包括继承的方法
getMethod(方法名,参数类型列表)
getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名,int.class,String.class)
 
//反射新建实例
clazz.newInstance();//执行无参构造创建对象
clazz.newInstance(222,"韦小宝");//执行有参构造创建对象
clazz.getConstructor(int.class,String.class)//获取构造方法
 
//反射调用成员变量
clazz.getDeclaredField(变量名);//获取变量
clazz.setAccessible(true);//使私有成员允许访问
f.set(实例,值);//为指定实例的变量赋值,静态变量,第一参数给null
f.get(实例);//访问指定实例变量的值,静态变量,第一参数给null
 
//反射调用成员方法
Method m = Clazz.getDeclaredMethod(方法名,参数类型列表);
m.setAccessible(true);//使私有方法允许被调用
m.invoke(实例,参数数据);//让指定实例来执行该方法

工厂模式简要介绍

推荐先观看最通俗易懂的讲解工厂模式

什么是工厂模式

个人简单的理解:工厂模式是建造者模式,为用户屏蔽了实例化对象的一些细节,可以为用户做一些数据转换等工作(对用户屏蔽),防止用户滥用构造函数,应用十分广泛,如单例模式也是使用了这个思想。

三种工厂模式简单介绍(其实就两种)

  1. 简单工厂模式:一个工厂类,提供一个静态方法,为用户生成对象,多态的时候使用。
  2. 工厂方法模式:提供一个抽象方法,这样是为了纠正简单工厂的缺点(简单工厂在扩展的时候会违反开闭原则)。工厂方法模式在扩展的时候只需要继承抽象基工厂即可。
  3. 抽象工厂模式:其实是有多个抽象方法,可以生成不同大类的产品,不过它扩展大类产品的时候还是要修改基类,违反了开闭原则。当抽象工厂模式只有一个产品体系的话就会退化成工厂方法模式。

IOC

简介

IOC:控制反转,我们不再需要主动的new对象,而是被动的接受对象。将对象交给容器管理,然后容器通过工厂模式为我们用户提供对象。

将以上三种技术结合起来实现一个简易的IOC容器

首先写一个普通类People

public class People {
    private String name;
    private String age;

    @Override
    public String toString() {
        return "name: "+ name + "age: "+ age;
    }
}

写一个beans.xml,将我们的普通类注册进去

<?xml version="1.0" encoding="utf-8" ?>
<xml>
    <bean id="people" class="People">
        <property name="name">翔掌门</property>
        <property name="age">18</property>
    </bean>
</xml>

写一个工厂BeanFactory

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class BeanFactory {
    // 底层是一个hashmap
    private static HashMap<String,Object> beanMap = new HashMap<>();
    public static Object getBean(String id) {
        return beanMap.get(id);
    }
    static {
        try {
            init();
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (SAXException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    // 在这里完善hashmap
    private static void init() throws ParserConfigurationException, IOException, SAXException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        Document document = documentBuilder.parse("resource/beans.xml");
        NodeList beans = document.getElementsByTagName("bean");
        for (int i = 0; i < beans.getLength(); i++) {
            // 获取<bean>
            Element bean = (Element) beans.item(i);
            // 将这个bean的属性先存储起来
            Map<String,String> attrs = getAttrs(bean.getChildNodes());
            // 反射获取类信息
            Class<?> clazz = Class.forName(bean.getAttribute("class"));
            Object instance = clazz.newInstance();
            Field[] fields = clazz.getDeclaredFields();
            for (int j = 0; j < fields.length; j++) {
                Field field = fields[j];
                // 让私有变量可以访问
                field.setAccessible(true);
                // filed的名字就是示例变量的名字
                field.set(instance,attrs.get(field.getName()));
            }
            // 变量设置完毕
            beanMap.put(bean.getAttribute("id"),instance);
        }
    }

    private static Map<String, String> getAttrs(NodeList childNodes) {
        Map<String,String> map = new HashMap<>();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node node = childNodes.item(i);

            if(node.getNodeType() == Node.ELEMENT_NODE) {
                Element el = (Element) node;
                String key = el.getAttribute("name");
                String value = el.getFirstChild().getNodeValue();
                map.put(key,value);
            }
        }
        return map;
    }
}

核心就是getBean方法和beanMap。

加载工厂类的时候,将beans.xml解析,获取所有对象以及属性,通过反射构造对象,放在beanMap中。

运行

public class Demo2 {
    public static void main(String[] args) {
        Object people = BeanFactory.getBean("people");
        System.out.println(people);
    }
}

posted @ 2022-12-10 16:02  BurningShy  阅读(65)  评论(0编辑  收藏  举报