反射机制与工厂设计模式

更新时间:2023-11-19 14:04:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

[零基础学JAVA]Java SE应用部分-36.反射机制与工厂设计模式

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

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(\); }catch (Exception e){} try{

p = (Person)c.newInstance(); }catch (Exception e){}

//上面两行代码也可以使用下面一行代码取代哈~

//

p

=

(Person)Class.forName(\ p.setName(\); 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(\); 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(\); Constructor[] cs = c.getConstructors(); Object obj[] = new Object[]{\,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(\); 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(\,\); p.setProperty(\,\); p.setProperty(\,\); 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(\,\); pro.setProperty(\,\); //保存在文件之中 try{

pro.storeToXML(new

FileOutputStream(new

File(\)),\); }catch (Exception e){} }

private void load(){

File f = new File(\); 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()进行反射加载完成

//进行创建 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://www.bwwdw.com/article/n3xv.html

Top