[转] 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()进行反射加载完成。


转自:http://bbs.51cto.com/thread-559958-1.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值