本季目标
Java的反射机制
工厂模式综合讲解
工厂模式综合讲解
1、什么叫反射
Java.lang.reflect包下
正常情况下我们可以通过类实例化一个对象,那么通过反射实际上就可以通过一个对象得到此类完整的包.类名称。
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());
}
}
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[i]);
}
}
}
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[i]);
}
}
}
2、研究Class类
Class类的构造方法被私有化了,外部无法直接看见,所以其内部必然有一个方法可以取得Class 实例。
public static Class<?> forName(String className) throws ClassNotFoundException
此方法可以返回Class类的实例,此方法接收一个完整的包.类名称。
通过newInstance方法,可以将传入的完整的字符串(包.类名称)实例化。
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());
}
}
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());
}
}
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());
}
}
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();
}
}
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();
}
}
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完成。
使用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.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();
}
}
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()进行反射加载完成。
####################Michael分割线######################
本文转自redking51CTO博客,原文链接:http://blog.51cto.com/redking/141195
,如需转载请自行联系原作者