反射與工廠模式之間不可告人的祕密
認識反射機制
初識反射
反射是指物件的反向操作,既然是反向操作處理。那先來觀察一下正向的操作。
import java.util.Date;
public static void main (String[] args){
Date date = new Date();
}
}
以上便是我們一般關於物件的處理流程:根據包名.類名 找到類;
所謂“反”指的是根據物件取得來取得物件的來源資訊,而這個“反”的操作核心的處理就在於Object類的一個方法:取得Class物件:
public final native Class<?> getClass ();
該方法返回的是一個Class類的物件,這個Class描述的就是類。
如:呼叫getClass()方法
package reflect;
import java.util.Date;
public class Test {
public static void main(String[] args) {
Date date = new Date();
System.out.println(date.getClass());
}
}
//+++++++++++++++++++++++++++++++++++
class java.util.Date
此時便是通過物件去的了物件的來源,這就是“反”的本質。
在反射的世界裡面,看重的不再是一個物件,而是物件身後的組成(類、構造、成員等)
Class類物件的三種例項化模式
Class類是描述整個類的概念,也是整個反射的操作源頭,在使用Class類的時候魚藥關注的依然是這個類的物件。而這個類的物件的產生模式一共有三種:
- 任何類的例項化物件都可以通過Object類中的getClass()方法取得Class類物件。
- “類.class”:直接根據某個具體的類來取得Class類的例項化物件。
- 使用Class類提供的方法:public static Class< ?>forName(String className) throws ClassNotFoundException
使用Class.forName()方法:
package reflect;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> cls = Class.forName("java.util.Date");
System.out.println(cls.getName());
}
}
//++++++++++++++++++++++++++++++++++++++++++++
java.util.Date
在以上給出的三個方法中可以發現,除了第一種方法會產生Date類物件的例項化物件之外,其他的兩種都不會產生Date類的例項化物件。於是取得了Class類物件有一個最直接的好處:可以通過反射例項化物件,在Class類中定義有如下方法:
public T newInstance()throws InstantiationException,IllegalAccessException
如:
public class Test {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class<?> cls = Class.forName("java.util.Date");
Object obj = cls.newInstance();//結果和下句結果相同
// Object obj = new java.util.Date();
System.out.println(obj);
}
}
//+++++++++++++++++++++
Fri Jun 01 15:59:46 GMT+08:00 2018
所以除了new之外,物件的例項化模式有了新的方式。
取得lClass物件就意味著取得了一些指定類的操作許可權。
反射與工廠設計模式
工廠設計模式的原則:如果是自己編寫的介面,想要取得本介面的例項化物件,最好使用工廠類來設計。單是也需要知道傳統設計模式所帶來的問題:
interface Ifruit {//介面
public void eat();
}
class Apple implements Ifruit{//實現
@Override
public void eat() {
System.out.println("i like apple");
}
}
class Factory {//工廠模式,代替生產物件
private Factory() {};
public static Ifruit getInstance(String ClassName) {
if ("apple".equals(ClassName)) {
return new Apple();
}
return null;
}
}
public class Test{
public static void main(String[] args) {
Ifruit ifruit = Factory.getInstance("apple");
ifruit.eat();
}
}
//+++++++++++++++++++++++++++++++++++
i like apple
傳統工廠類在實際開發中根本用不到。因為如果每增加一個介面就需要修改工廠類
如果想要解決關鍵字new帶來的問題,最好的做法就是通過反射來完成處理,因為Class類可以使用newInstant()例項化物件,同時Class.forName()能夠接收類名稱。
修改:
interface Ifruit {//
public void eat();
}
class Apple implements Ifruit{
@Override
public void eat() {
System.out.println("i like apple");
}
}
class Banana implements Ifruit{
@Override
public void eat() {
System.out.println("i like banana");
}
}
class Factory {
private Factory() {};
public static Ifruit getInstance(String ClassName) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
Ifruit ifruit = (Ifruit)Class.forName(ClassName).newInstance();//用newInstance產生例項化物件
return ifruit;
}
}
public class Test{
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
Ifruit ifruit = Factory.getInstance("reflect.Apple");//傳入完整的類名
ifruit.eat();
}
}
//+++++++++++++++++++++++++++++++++++
i like apple
引入反射後,每當新增介面子類,無需修改工廠類帶就可以很方便的進行介面子類擴充套件,相當於動態的在new傳入的物件,以上就是簡單工廠模式。