反射、工廠模式、IOC容器淺嘗 一篇入門
阿新 • • 發佈:2022-12-10
反射
什麼是反射?
個人目前理解:反射是在程式執行期間獲取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);
}
}