Java的反射机制 工厂模式综合讲解【转载自51CTO】
生活随笔
收集整理的這篇文章主要介紹了
Java的反射机制 工厂模式综合讲解【转载自51CTO】
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
2019獨角獸企業重金招聘Python工程師標準>>>
Java的反射機制
工廠模式綜合講解
1、什么叫反射
Java.lang.reflect包下
正常情況下我們可以通過類實例化一個對象,那么通過反射實際上就可以通過一個對象得到此類完整的包.類名稱。
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();
//假設現在不知道p是那個類的對象,則可以通過反射機制找到
Class c = null;
c = p.getClass();
System.out.println(c.getName());
}
}
看下效果:
除了可以找到對象所在的包.類名稱,實際上也可以把所有的方法名稱列出來。
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();
//假設現在不知道p是那個類的對象,則可以通過反射機制找到
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類的構造方法被私有化了,外部無法直接看見,所以其內部必然有一個方法可以取得Class 實例。
public static Class<?> forName(String className) throws ClassNotFoundException
此方法可以返回Class類的實例,此方法接收一個完整的包.類名稱。
通過newInstance方法,可以將傳入的完整的字符串(包.類名稱)實例化。
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());
}
}
如果要使用以上的代碼去實例化一個對象,則必須有一個前途條件:在對象所在的類中必須有一個無參構造方法,如果沒有此無參構造,則肯定會出現錯誤。
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());
}
}
在此時如果想繼續通過此操作為對象進行實例化,則可以通過構造方法類(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};
//一個類中會有多個構造方法,所以此時返回一個數組
p = (Person)cs[0].newInstance(obj);
}catch (Exception e){
System.out.println(e);
}
System.out.println(p.getName()+"--->"+p.getAge());
}
}
反射機制實際上是我們所有框架的一個基礎,那么現在就利用反射機制完成一個高可擴展性的工廠設計。
回顧:工廠設計
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();
}
}
客戶端只與工廠和直接的接口有關了,而與其他的無關,但是有個問題,如果現在要擴展了子類,則工廠也必須同時進行修改。那么有沒有一種方法,可以讓子類擴充之后不去修改工廠呢?肯定是有的,通過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();
}
}
但是此程序依然有一個缺點,現在的輸入的包.類名稱實際上長度非常的短,如果包.類名稱的長度過長了,則在使用的時候就比較麻煩了。所以最好可以找個代號進行替代。
使用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();
//進一步擴展,現在可以由用戶自己輸入要使用的類型
Fruit f = Factory.getFruit(p.getProperty(str));
f.grow();
}
}
如果現在再增加子類呢?
屬性文件肯定不夠了。
所以此時為了達到好的效果,則最好可以將屬性保存起來,之后通過修改保存的文件達到屬性的擴充。
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();
}
//設置一個返回方法
public Properties getPro(){
return this.pro;
}
//從文件中讀出屬性,如果文件不存在,則創建一個默認的
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{
//進行創建
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();
//進一步擴展,現在可以由用戶自己輸入要使用的類型
Fruit f = Factory.getFruit(p.getProperty(str));
f.grow();
}
}
如果此時要想新增加可以操作的子類,則就需要配置fruit.xml文件即可。
此種代碼是典型的配置與程序相分離,程序直接有配置文件有關。某一個部分的修改不影響其他程序。—— 思想必須建立起來。
總結
對象的產生到底有多少種方法了:
· 直接用new關鍵字產生:直接,但是代碼間會產生嚴重的耦合性
· 可以通過工廠傳遞引用:直接,但是必須考慮到代碼以后的可維護性
· 通過對象克隆可以完成
· 通過Class.forName()進行反射加載完成。
轉載于:https://my.oschina.net/liu-xuewei/blog/66777
總結
以上是生活随笔為你收集整理的Java的反射机制 工厂模式综合讲解【转载自51CTO】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我圣贤为何发起第三方插件商店和桌面应用商
- 下一篇: 头脑风暴是如何毁掉创意的?