當(dāng)前位置:
首頁 >
Java的反射机制 工厂模式综合讲解【转载自51CTO】
發(fā)布時(shí)間:2025/6/15
54
豆豆
生活随笔
收集整理的這篇文章主要介紹了
Java的反射机制 工厂模式综合讲解【转载自51CTO】
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
Java的反射機(jī)制
工廠模式綜合講解
1、什么叫反射
Java.lang.reflect包下
正常情況下我們可以通過類實(shí)例化一個(gè)對象,那么通過反射實(shí)際上就可以通過一個(gè)對象得到此類完整的包.類名稱。
package org.michael;
class Person{
private String name;
private int age;
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
}
public class Demo01{
public static void main(String args[]){
Person p = new Person();
//假設(shè)現(xiàn)在不知道p是那個(gè)類的對象,則可以通過反射機(jī)制找到
Class c = null;
c = p.getClass();
System.out.println(c.getName());
}
}
看下效果:
除了可以找到對象所在的包.類名稱,實(shí)際上也可以把所有的方法名稱列出來。
package org.michael;
import java.lang.reflect.*;
class Person{
private String name;
private int age;
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
}
public class Demo02{
public static void main(String args[]){
Person p = new Person();
//假設(shè)現(xiàn)在不知道p是那個(gè)類的對象,則可以通過反射機(jī)制找到
Class c = null;
c = p.getClass();
Method m[] = c.getMethods();
for(int i=0;i<m.length;i++){
System.out.println(m);
}
}
}
2、研究Class類
Class類的構(gòu)造方法被私有化了,外部無法直接看見,所以其內(nèi)部必然有一個(gè)方法可以取得Class 實(shí)例。
public static Class<?> forName(String className) throws ClassNotFoundException
此方法可以返回Class類的實(shí)例,此方法接收一個(gè)完整的包.類名稱。
通過newInstance方法,可以將傳入的完整的字符串(包.類名稱)實(shí)例化。
package org.michael;
import java.lang.reflect.*;
class Person{
private String name;
private int age;
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
}
public class Demo03{
public static void main(String args[]){
Person p = null;
Class c = null;
try{
c = Class.forName("org.michael.Person");
}catch (Exception e){}
try{
p = (Person)c.newInstance();
}catch (Exception e){}
//上面兩行代碼也可以使用下面一行代碼取代哈~
// p = (Person)Class.forName("org.michael.Person").newInstance();
p.setName("Michael");
p.setAge(30);
System.out.println(p.getName()+"--->"+p.getAge());
}
}
如果要使用以上的代碼去實(shí)例化一個(gè)對象,則必須有一個(gè)前途條件:在對象所在的類中必須有一個(gè)無參構(gòu)造方法,如果沒有此無參構(gòu)造,則肯定會出現(xiàn)錯誤。
package org.michael;
import java.lang.reflect.*;
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
}
public class Demo04{
public static void main(String args[]){
Person p = null;
Class c = null;
try{
c = Class.forName("org.michael.Person");
p = (Person)c.newInstance();
}catch (Exception e){
System.out.println(e);
}
System.out.println(p.getName()+"--->"+p.getAge());
}
}
在此時(shí)如果想繼續(xù)通過此操作為對象進(jìn)行實(shí)例化,則可以通過構(gòu)造方法類(Constructor)完成。
package org.michael;
import java.lang.reflect.*;
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
}
public class Demo05{
public static void main(String args[]){
Person p = null;
Class c = null;
try{
c = Class.forName("org.michael.Person");
Constructor[] cs = c.getConstructors();
Object obj[] = new Object[]{"Michael",30};
//一個(gè)類中會有多個(gè)構(gòu)造方法,所以此時(shí)返回一個(gè)數(shù)組
p = (Person)cs[0].newInstance(obj);
}catch (Exception e){
System.out.println(e);
}
System.out.println(p.getName()+"--->"+p.getAge());
}
}
反射機(jī)制實(shí)際上是我們所有框架的一個(gè)基礎(chǔ),那么現(xiàn)在就利用反射機(jī)制完成一個(gè)高可擴(kuò)展性的工廠設(shè)計(jì)。
回顧:工廠設(shè)計(jì)
interface Fruit{
public void grow();
public void eat();
}
class Apple implements Fruit{
public void grow(){
System.out.println("蘋果在生長...");
}
public void eat(){
System.out.println("吃蘋果...");
}
}
class Orange implements Fruit{
public void grow(){
System.out.println("橘子在生長...");
}
public void eat(){
System.out.println("吃橘子...");
}
}
class Factory{
public static Fruit getFruit(int i){
Fruit f = null;
if (i==1){
f = new Apple();
}
if (i==2){
f = new Orange();
}
return f;
}
}
public class Demo06{
public static void main(String args[]){
Fruit f = Factory.getFruit(1);
f.grow();
}
}
客戶端只與工廠和直接的接口有關(guān)了,而與其他的無關(guān),但是有個(gè)問題,如果現(xiàn)在要擴(kuò)展了子類,則工廠也必須同時(shí)進(jìn)行修改。那么有沒有一種方法,可以讓子類擴(kuò)充之后不去修改工廠呢?肯定是有的,通過Class.forName 完成。
interface Fruit{
public void grow();
public void eat();
}
class Apple implements Fruit{
public void grow(){
System.out.println("蘋果在生長...");
}
public void eat(){
System.out.println("吃蘋果...");
}
}
class Orange implements Fruit{
public void grow(){
System.out.println("橘子在生長...");
}
public void eat(){
System.out.println("吃橘子...");
}
}
class Banana implements Fruit{
public void grow(){
System.out.println("香蕉在生長...");
}
public void eat(){
System.out.println("吃香蕉...");
}
}
class Factory{
public static Fruit getFruit(String className){
Fruit f = null;
try{
f = (Fruit)Class.forName(className).newInstance();
}catch (Exception e){}
return f;
}
}
public class Demo07{
public static void main(String args[]){
Fruit f = Factory.getFruit("Banana");
f.grow();
}
}
但是此程序依然有一個(gè)缺點(diǎn),現(xiàn)在的輸入的包.類名稱實(shí)際上長度非常的短,如果包.類名稱的長度過長了,則在使用的時(shí)候就比較麻煩了。所以最好可以找個(gè)代號進(jìn)行替代。
使用Hashtable的子類 —— Properties完成。
import java.util.*;
import java.io.*;
interface Fruit{
public void grow();
public void eat();
}
class Apple implements Fruit{
public void grow(){
System.out.println("蘋果在生長...");
}
public void eat(){
System.out.println("吃蘋果...");
}
}
class Orange implements Fruit{
public void grow(){
System.out.println("橘子在生長...");
}
public void eat(){
System.out.println("吃橘子...");
}
}
class Banana implements Fruit{
public void grow(){
System.out.println("香蕉在生長...");
}
public void eat(){
System.out.println("吃香蕉...");
}
}
class Factory{
public static Fruit getFruit(String className){
Fruit f = null;
try{
f = (Fruit)Class.forName(className).newInstance();
}catch (Exception e){}
return f;
}
}
class InputData{
private BufferedReader buf = null;
public InputData(){
this.buf = new BufferedReader(new InputStreamReader(System.in));
}
public String getString(){
String str = null;
try{
str = this.buf.readLine();
}catch (Exception e){}
return str;
}
}
public class Demo08{
public static void main(String args[]){
Properties p = new Properties();
p.setProperty("a","Apple");
p.setProperty("o","Orange");
p.setProperty("b","Banana");
System.out.println(p);
System.out.print("請選擇所需要的類型:");
String str = new InputData().getString();
//進(jìn)一步擴(kuò)展,現(xiàn)在可以由用戶自己輸入要使用的類型
Fruit f = Factory.getFruit(p.getProperty(str));
f.grow();
}
}
如果現(xiàn)在再增加子類呢?
屬性文件肯定不夠了。
所以此時(shí)為了達(dá)到好的效果,則最好可以將屬性保存起來,之后通過修改保存的文件達(dá)到屬性的擴(kuò)充。
import java.util.*;
import java.io.*;
interface Fruit{
public void grow();
public void eat();
}
class Apple implements Fruit{
public void grow(){
System.out.println("蘋果在生長...");
}
public void eat(){
System.out.println("吃蘋果...");
}
}
class Orange implements Fruit{
public void grow(){
System.out.println("橘子在生長...");
}
public void eat(){
System.out.println("吃橘子...");
}
}
class Banana implements Fruit{
public void grow(){
System.out.println("香蕉在生長...");
}
public void eat(){
System.out.println("吃香蕉...");
}
}
class Factory{
public static Fruit getFruit(String className){
Fruit f = null;
try{
f = (Fruit)Class.forName(className).newInstance();
}catch (Exception e){}
return f;
}
}
class PropertyOperate{
private Properties pro = null;
public PropertyOperate(){
this.pro = new Properties();
this.load();
}
//設(shè)置一個(gè)返回方法
public Properties getPro(){
return this.pro;
}
//從文件中讀出屬性,如果文件不存在,則創(chuàng)建一個(gè)默認(rèn)的
private void save(){
pro.setProperty("a","Apple");
pro.setProperty("o","Orange");
//保存在文件之中
try{
pro.storeToXML(new FileOutputStream(new File("e:\\fruit.xml")),"FRUIT FACTORY");
}catch (Exception e){}
}
private void load(){
File f = new File("e:\\fruit.xml");
if(f.exists()){
//文件存在則可以讀取
try{
pro.loadFromXML(new FileInputStream(f));
}catch (Exception e){}
}else{
//進(jìn)行創(chuàng)建
this.save();
}
}
}
class InputData{
private BufferedReader buf = null;
public InputData(){
this.buf = new BufferedReader(new InputStreamReader(System.in));
}
public String getString(){
String str = null;
try{
str = this.buf.readLine();
}catch(Exception e){}
return str;
}
}
public class Demo09{
public static void main(String args[]){
Properties p = new PropertyOperate().getPro();
System.out.println(p);
System.out.print("請選擇所需要的類型:");
String str = new InputData().getString();
//進(jìn)一步擴(kuò)展,現(xiàn)在可以由用戶自己輸入要使用的類型
Fruit f = Factory.getFruit(p.getProperty(str));
f.grow();
}
}
如果此時(shí)要想新增加可以操作的子類,則就需要配置fruit.xml文件即可。
此種代碼是典型的配置與程序相分離,程序直接有配置文件有關(guān)。某一個(gè)部分的修改不影響其他程序。—— 思想必須建立起來。
總結(jié)
對象的產(chǎn)生到底有多少種方法了:
· 直接用new關(guān)鍵字產(chǎn)生:直接,但是代碼間會產(chǎn)生嚴(yán)重的耦合性
· 可以通過工廠傳遞引用:直接,但是必須考慮到代碼以后的可維護(hù)性
· 通過對象克隆可以完成
· 通過Class.forName()進(jìn)行反射加載完成。
轉(zhuǎn)載于:https://my.oschina.net/liu-xuewei/blog/66777
總結(jié)
以上是生活随笔為你收集整理的Java的反射机制 工厂模式综合讲解【转载自51CTO】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我圣贤为何发起第三方插件商店和桌面应用商
- 下一篇: Java的访问控制