反射、工厂模式、IOC容器浅尝 一篇入门
反射
什么是反射?
个人目前理解:反射是在程序运行期间获取class信息,用这些信息做一些操作,例如本文后续要用的实例化一个对象以及为属性赋值。
如何获取class信息
- 调用对象的getClass方法
- 调用类的class属性
- 使用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(实例,参数数据);//让指定实例来执行该方法
工厂模式简要介绍
推荐先观看最通俗易懂的讲解工厂模式
什么是工厂模式
个人简单的理解:工厂模式是建造者模式,为用户屏蔽了实例化对象的一些细节,可以为用户做一些数据转换等工作(对用户屏蔽),防止用户滥用构造函数,应用十分广泛,如单例模式也是使用了这个思想。
三种工厂模式简单介绍(其实就两种)
- 简单工厂模式:一个工厂类,提供一个静态方法,为用户生成对象,多态的时候使用。
- 工厂方法模式:提供一个抽象方法,这样是为了纠正简单工厂的缺点(简单工厂在扩展的时候会违反开闭原则)。工厂方法模式在扩展的时候只需要继承抽象基工厂即可。
- 抽象工厂模式:其实是有多个抽象方法,可以生成不同大类的产品,不过它扩展大类产品的时候还是要修改基类,违反了开闭原则。当抽象工厂模式只有一个产品体系的话就会退化成工厂方法模式。
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);
}
}