1. 程式人生 > >構建自己的Java Web框架(三)之JAVA反射機制

構建自己的Java Web框架(三)之JAVA反射機制

        JAVA反射機制是在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制。

       JAVA反射(放射)機制:“程式執行時,允許改變程式結構或變數型別,這種語言稱為動態語言”。從這個觀點看,Perl,Python,Ruby是動態語言,C++,Java,C#不是動態語言。但是JAVA有著一個非常突出的動態相關機制:Reflection,用在Java身上指的是我們可以於執行時載入、探知、使用編譯期間完全未知的classes。換句話說,Java程式可以載入一個執行時才得知名稱的class,獲悉其完整構造(但不包括methods定義),並生成其物件實體、或對其fields設值、或喚起其methods。

    Java反射機制主要提供了以下功能: 在執行時判斷任意一個物件所屬的類;在執行時構造任意一個類的物件;在執行時判斷任意一個類所具有的成員變數和方法;在執行時呼叫任意一個物件的方法;生成動態代理。
    (以上來自百度百科)
    

    上面的定義都是一些解釋,可能會比較繞,我們還是來點例項說明下:

1、獲取Class物件有三種方式:

    //第一種方式:  
    Class c1 = Class.forName("MyClass");  
    //第二種方式:  
    //java中每個型別都有class 屬性.  
    Class c2 = MyClass.class;  
       
    //第三種方式:  
    //java語言中任何一個java物件都有getClass 方法  
    MyClass myclass = new MyClass();  
    Class c3 = myclass.getClass(); //c3是執行時類 (e的執行時類是MyClass)

2、建立物件:獲取類以後我們來建立它的物件,利用newInstance
 Class c =Class.forName("MyClass");  
  
	//建立此Class 物件所表示的類的一個新例項  
	Object obj = c.newInstance(); //呼叫了MyClass的無引數構造方法.
3、獲取屬性:分為所有的屬性和指定的屬性:

    a.先看獲取所有的屬性的寫法:

//獲取整個類  
Class c = Class.forName("java.lang.Integer");  
  //獲取所有的屬性?  
Field[] fs = c.getDeclaredFields();  

//定義可變長的字串,用來儲存屬性  
StringBuffer sb = new StringBuffer();  
//通過追加的方法,將每個屬性拼接到此字串中  
//最外邊的public定義  
sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");  
//裡邊的每一個屬性  
for(Field field:fs){  
	sb.append("\t");//空格  
	sb.append(Modifier.toString(field.getModifiers())+" ");//獲得屬性的修飾符,例如public,static等等  
	sb.append(field.getType().getSimpleName() + " ");//屬性的型別的名字  
	sb.append(field.getName()+";\n");//屬性的名字+回車  
}  

sb.append("}");  

System.out.println(sb); 

b.獲取特定的屬性,對比著傳統的方法來學習:
public static void main(String[] args) throws Exception{  
			  
	//以前的方式:  
	/* 
	User u = new User(); 
	u.age = 12; //set 
	System.out.println(u.age); //get 
	*/  
			  
	//獲取類  
	Class user = Class.forName("User");  
	//獲取id屬性  
	Field idF = user.getDeclaredField("id");  
	//例項化這個類賦給o  
	Object obj = user.newInstance();  
	//打破封裝  
	idF.setAccessible(true); //使用反射機制可以打破封裝性,導致了java物件的屬性不安全。  
	//給o物件的id屬性賦值"110"  
	idF.set(obj, "110"); //set  
	//get  
	System.out.println(idF.get(obj));  
}

4、獲取方法,和構造方法,來看一下關鍵字:

類獲取

含義

getClass()

獲取類

方法關鍵字

含義

getDeclaredMethods()

獲取所有的方法

getReturnType()

獲得方法的放回型別

getParameterTypes()

獲得方法的傳入引數型別

getDeclaredMethod("方法名",引數型別.class,……)

獲得特定的方法

構造方法關鍵字

含義

getDeclaredConstructors()

獲取所有的構造方法

getDeclaredConstructor(引數型別.class,……)

獲取特定的構造方法

父類和父介面

含義

getSuperclass()

獲取某類的父類

getInterfaces()

獲取某類實現的介面


這樣我們就可以獲得類的各種內容,進行了反編譯。對於JAVA這種先編譯再執行的語言來說,反射機制可以使程式碼更加靈活,更加容易實現面向物件。

接下來較少Java反射的各種使用案例:

1、通過一個物件獲得完整的包名和類名

package Reflect;

/**
 * 通過一個物件獲得完整的包名和類名
 * */
class Demo{
	//other codes...
}
 
class hello{
	public static void main(String[] args) {
		Demo demo=new Demo();
		System.out.println(demo.getClass().getName());
	}
}

【執行結果】:Reflect.Demo
新增一句:所有類的物件其實都是Class的例項。

2、例項化Class類物件

package Reflect;
class Demo{
	//other codes...
}
 
class hello{
	public static void main(String[] args) {
		Class<?> demo1=null;
		Class<?> demo2=null;
		Class<?> demo3=null;
		try{
			//一般儘量採用這種形式
			demo1=Class.forName("Reflect.Demo");
		}catch(Exception e){
			e.printStackTrace();
		}
		demo2=new Demo().getClass();
		demo3=Demo.class;
		 
		System.out.println("類名稱   "+demo1.getName());
		System.out.println("類名稱   "+demo2.getName());
		System.out.println("類名稱   "+demo3.getName());
		 
	}
}
【執行結果】:
類名稱   Reflect.Demo
類名稱   Reflect.Demo
類名稱   Reflect.Demo

3、通過Class例項化其他類的物件 通過無參構造例項化物件

package Reflect;

class Person{
	 
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString(){
		return "["+this.name+"  "+this.age+"]";
	}
	private String name;
	private int age;
}
 
class hello{
	public static void main(String[] args) {
		Class<?> demo=null;
		try{
			demo=Class.forName("Reflect.Person");
		}catch (Exception e) {
			e.printStackTrace();
		}
		Person per=null;
		try {
			per=(Person)demo.newInstance();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		per.setName("Rollen");
		per.setAge(20);
		System.out.println(per);
	}
}
【執行結果】:
[Rollen  20]

但是注意一下,當我們把Person中的預設的無參建構函式取消的時候,比如自己定義只定義一個有引數的建構函式之後,會出現錯誤:
比如定義了一個建構函式:

public Person(String name, int age) {
	this.age=age;
	this.name=name;
}
java.lang.InstantiationException: Reflect.Person
at java.lang.Class.newInstance0(Class.java:340)
at java.lang.Class.newInstance(Class.java:308)
at Reflect.hello.main(hello.java:39)
Exception in thread "main" java.lang.NullPointerException at Reflect.hello.main(hello.java:47

4、通過Class呼叫其他類中的建構函式 (也可以通過這種方式通過Class建立其他類的物件)
package Reflect;

import java.lang.reflect.Constructor;
 
class Person{
	 
	public Person() {
		 
	}
	public Person(String name){
		this.name=name;
	}
	public Person(int age){
		this.age=age;
	}
	public Person(String name, int age) {
		this.age=age;
		this.name=name;
	}
	public String getName() {
		return name;
	}
	public int getAge() {
		return age;
	}
	@Override
	public String toString(){
		return "["+this.name+"  "+this.age+"]";
	}
	private String name;
	private int age;
}
 
class hello{
	public static void main(String[] args) {
		Class<?> demo=null;
		try{
			demo=Class.forName("Reflect.Person");
		}catch (Exception e) {
			e.printStackTrace();
		}
		Person per1=null;
		Person per2=null;
		Person per3=null;
		Person per4=null;
		//取得全部的建構函式
		Constructor<?> cons[]=demo.getConstructors();
		try{
			per1=(Person)cons[0].newInstance();
			per2=(Person)cons[1].newInstance("Rollen");
			per3=(Person)cons[2].newInstance(20);
			per4=(Person)cons[3].newInstance("Rollen",20);
		}catch(Exception e){
			e.printStackTrace();
		}
		System.out.println(per1);
		System.out.println(per2);
		System.out.println(per3);
		System.out.println(per4);
	}
}

【執行結果】:
[null  0]
[Rollen  0]
[null  20]
[Rollen  20]

5、返回一個類實現的介面

package Reflect;

interface China{
	public static final String name="Rollen";
	public static  int age=20;
	public void sayChina();
	public void sayHello(String name, int age);
}
 
class Person implements China{
	public Person() {
		 
	}
	public Person(String sex){
		this.sex=sex;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		this.sex = sex;
	}
	@Override
	public void sayChina(){
		System.out.println("hello ,china");
	}
	@Override
	public void sayHello(String name, int age){
		System.out.println(name+"  "+age);
	}
	private String sex;
}
 
class hello{
	public static void main(String[] args) {
		Class<?> demo=null;
		try{
			demo=Class.forName("Reflect.Person");
		}catch (Exception e) {
			e.printStackTrace();
		}
		//儲存所有的介面
		Class<?> intes[]=demo.getInterfaces();
		for (int i = 0; i < intes.length; i++) {
			System.out.println("實現的介面   "+intes[i].getName());
		}
	}
}
【執行結果】:
實現的介面   Reflect.China

6、取得其他類中的父類

class hello{
	public static void main(String[] args) {
		Class<?> demo=null;
		try{
			demo=Class.forName("Reflect.Person");
		}catch (Exception e) {
			e.printStackTrace();
		}
		//取得父類
		Class<?> temp=demo.getSuperclass();
		System.out.println("繼承的父類為:   "+temp.getName());
	}
}
【執行結果】
繼承的父類為:   java.lang.Object

7、獲得其他類中的全部建構函式
class hello{
	public static void main(String[] args) {
		Class<?> demo=null;
		try{
			demo=Class.forName("Reflect.Person");
		}catch (Exception e) {
			e.printStackTrace();
		}
		Constructor<?> cons[]=demo.getConstructors();
		for (int i = 0; i < cons.length; i++) {
			System.out.println("構造方法:  "+cons[i]);
		}
	}
}
【執行結果】
構造方法:  public Reflect.Person()
構造方法:  public Reflect.Person(java.lang.String)

但是細心的讀者會發現,上面的建構函式沒有public 或者private這一類的修飾符 , 前面我們有提到-----使用反射機制可以打破封裝性,導致了java物件的屬性不安全。

下面這個例子我們就來獲取修飾符:

class hello{
	public static void main(String[] args) {
		Class<?> demo=null;
		try{
			demo=Class.forName("Reflect.Person");
		}catch (Exception e) {
			e.printStackTrace();
		}
		Constructor<?> cons[]=demo.getConstructors();
		for (int i = 0; i < cons.length; i++) {
			Class<?> p[]=cons[i].getParameterTypes();
			System.out.print("構造方法:  ");
			int mo=cons[i].getModifiers();
			System.out.print(Modifier.toString(mo)+" ");
			System.out.print(cons[i].getName());
			System.out.print("(");
			for(int j=0;j<p.length;++j){
				System.out.print(p[j].getName()+" arg"+i);
				if(j<p.length-1){
					System.out.print(",");
				}
			}
			System.out.println("){}");
		}
	}
}
【執行結果】
構造方法:  public Reflect.Person(){}
構造方法:  public Reflect.Person(java.lang.String arg1){}

有時候一個方法可能還有異常,呵呵。下面看看:

class hello{
	public static void main(String[] args) {
		Class<?> demo=null;
		try{
			demo=Class.forName("Reflect.Person");
		}catch (Exception e) {
			e.printStackTrace();
		}
		Method method[]=demo.getMethods();
		for(int i=0;i<method.length;++i){
			Class<?> returnType=method[i].getReturnType();
			Class<?> para[]=method[i].getParameterTypes();
			int temp=method[i].getModifiers();
			System.out.print(Modifier.toString(temp)+" ");
			System.out.print(returnType.getName()+"  ");
			System.out.print(method[i].getName()+" ");
			System.out.print("(");
			for(int j=0;j<para.length;++j){
				System.out.print(para[j].getName()+" "+"arg"+j);
				if(j<para.length-1){
					System.out.print(",");
				}
			}
			Class<?> exce[]=method[i].getExceptionTypes();
			if(exce.length>0){
				System.out.print(") throws ");
				for(int k=0;k<exce.length;++k){
					System.out.print(exce[k].getName()+" ");
					if(k<exce.length-1){
						System.out.print(",");
					}
				}
			}else{
				System.out.print(")");
			}
			System.out.println();
		}
	}
}

【執行結果】:
public java.lang.String  getSex () 
public void  setSex (java.lang.String arg0) 
public void  sayChina () 
public void  sayHello (java.lang.String arg0,int arg1) 
public final native void  wait (long arg0) throws java.lang.InterruptedException 
public final void  wait () throws java.lang.InterruptedException 
public final void  wait (long arg0,int arg1) throws java.lang.InterruptedException 
public boolean  equals (java.lang.Object arg0) 
public java.lang.String  toString () 
public native int  hashCode () 
public final native java.lang.Class  getClass () 
public final native void  notify () 
public final native void  notifyAll () 

8、接下來讓我們取得其他類的全部屬性吧,最後我講這些整理在一起,也就是通過class取得一個類的全部框架
class hello {
	public static void main(String[] args) {
		Class<?> demo = null;
		try {
			demo = Class.forName("Reflect.Person");
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("===============本類屬性========================");
		// 取得本類的全部屬性
		Field[] field = demo.getDeclaredFields();
		for (int i = 0; i < field.length; i++) {
			// 許可權修飾符
			int mo = field[i].getModifiers();
			String priv = Modifier.toString(mo);
			// 屬性型別
			Class<?> type = field[i].getType();
			System.out.println(priv + " " + type.getName() + " "
					+ field[i].getName() + ";");
		}
		System.out.println("===============實現的介面或者父類的屬性========================");
		// 取得實現的介面或者父類的屬性
		Field[] filed1 = demo.getFields();
		for (int j = 0; j < filed1.length; j++) {
			// 許可權修飾符
			int mo = filed1[j].getModifiers();
			String priv = Modifier.toString(mo);
			// 屬性型別
			Class<?> type = filed1[j].getType();
			System.out.println(priv + " " + type.getName() + " "
					+ filed1[j].getName() + ";");
		}
	}
}

【執行結果】:
===============本類屬性========================
private java.lang.String sex;
===============實現的介面或者父類的屬性========================
public static final java.lang.String name;
public static final int age;

【案例】其實還可以通過反射呼叫其他類中的方法:

class hello {
	public static void main(String[] args) {
		Class<?> demo = null;
		try {
			demo = Class.forName("Reflect.Person");
		} catch (Exception e) {
			e.printStackTrace();
		}
		try{
			//呼叫Person類中的sayChina方法
			Method method=demo.getMethod("sayChina");
			method.invoke(demo.newInstance());
			//呼叫Person的sayHello方法
			method=demo.getMethod("sayHello", String.class, int.class); //帶有引數的方法呼叫
			method.invoke(demo.newInstance(),"Rollen",20);
			 
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
}
【執行結果】:
hello ,china
Rollen  20

9、呼叫其他類的set和get方法

class hello {
	public static void main(String[] args) {
		Class<?> demo = null;
		Object obj=null;
		try {
			demo = Class.forName("Reflect.Person");
		} catch (Exception e) {
			e.printStackTrace();
		}
		try{
		 obj=demo.newInstance();
		}catch (Exception e) {
			e.printStackTrace();
		}
		setter(obj,"Sex","男",String.class);
		getter(obj,"Sex");
	}
 
	/**
	 * @param obj
	 *            操作的物件
	 * @param att
	 *            操作的屬性
	 * */
	public static void getter(Object obj, String att) {
		try {
			Method method = obj.getClass().getMethod("get" + att);
			System.out.println(method.invoke(obj));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
	/**
	 * @param obj
	 *            操作的物件
	 * @param att
	 *            操作的屬性
	 * @param value
	 *            設定的值
	 * @param type
	 *            引數的屬性
	 * */
	public static void setter(Object obj, String att, Object value,
			Class<?> type) {
		try {
			Method method = obj.getClass().getMethod("set" + att, type);
			method.invoke(obj, value);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}// end class
【執行結果】:

10、通過反射操作屬性

class hello {
	public static void main(String[] args) throws Exception {
		Class<?> demo = null;
		Object obj = null;
 
		demo = Class.forName("Reflect.Person");
		obj = demo.newInstance();
 
		Field field = demo.getDeclaredField("sex");
		field.setAccessible(true);
		field.set(obj, "男");
		System.out.println(field.get(obj));
	}
}// end class

11、通過反射取得並修改陣列的資訊:
import java.lang.reflect.*;
class hello{
	public static void main(String[] args) {
		int[] temp={1,2,3,4,5};
		Class<?> demo=temp.getClass().getComponentType();
		System.out.println("陣列型別: "+demo.getName());
		System.out.println("陣列長度  "+Array.getLength(temp));
		System.out.println("陣列的第一個元素: "+Array.get(temp, 0));
		Array.set(temp, 0, 100);
		System.out.println("修改之後陣列第一個元素為: "+Array.get(temp, 0));
	}
}
【執行結果】:
陣列型別: int
陣列長度  5
陣列的第一個元素: 1
修改之後陣列第一個元素為: 100

12、通過反射修改陣列大小

class hello{
	public static void main(String[] args) {
		int[] temp={1,2,3,4,5,6,7,8,9};
		int[] newTemp=(int[])arrayInc(temp,15);
		print(newTemp);
		System.out.println("=====================");
		String[] atr={"a","b","c"};
		String[] str1=(String[])arrayInc(atr,8);
		print(str1);
	}
	 
	/**
	 * 修改陣列大小
	 * */
	public static Object arrayInc(Object obj,int len){
		Class<?> arr=obj.getClass().getComponentType();
		Object newArr=Array.newInstance(arr, len);
		int co=Array.getLength(obj);
		System.arraycopy(obj, 0, newArr, 0, co);
		return newArr;
	}
	/**
	 * 列印
	 * */
	public static void print(Object obj){
		Class<?> c =obj.getClass();
		if(!c.isArray()){
			return;
		}
		System.out.println("陣列長度為: "+Array.getLength(obj));
		for (int i = 0; i < Array.getLength(obj); i++) {
			System.out.print(Array.get(obj, i)+" ");
		}
	}
}
【執行結果】:
陣列長度為: 15
1 2 3 4 5 6 7 8 9 0 0 0 0 0 0
=====================
陣列長度為: 8
a b c null null null null null

13、動態代理

如何獲得類載入器:

class test{
 
}

class hello{
	public static void main(String[] args) {
		test t=new test();
		System.out.println("類載入器  "+t.getClass().getClassLoader().getClass().getName());
	}
}

【程式輸出】:

類載入器  sun.misc.Launcher$AppClassLoader

其實在java中有三種類類載入器。
1)Bootstrap ClassLoader 此載入器採用c++編寫,一般開發中很少見;
2)Extension ClassLoader 用來進行擴充套件類的載入,一般對應的是jre\lib\ext目錄中的類;
3)AppClassLoader 載入classpath指定的類,是最常用的載入器。同時也是java中預設的載入器。

如果想要完成動態代理,首先需要定義一個InvocationHandler介面的子類,已完成代理的具體操作。

package Reflect;
import java.lang.reflect.*;
 
//定義專案介面
interface Subject {
	public String say(String name, int age);
}
 
// 定義真實專案
class RealSubject implements Subject {
	@Override
	public String say(String name, int age) {
		return name + "  " + age;
	}
}
 
class MyInvocationHandler implements InvocationHandler {
	private Object obj = null;
 
	public Object bind(Object obj) {
		this.obj = obj;
		return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
				.getClass().getInterfaces(), this);
	}
 
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object temp = method.invoke(this.obj, args);
		return temp;
	}
}
 
class hello {
	public static void main(String[] args) {
		MyInvocationHandler demo = new MyInvocationHandler();
		Subject sub = (Subject) demo.bind(new RealSubject());
		String info = sub.say("Rollen", 20);
		System.out.println(info);
	}
}
【執行結果】:
Rollen  20

類的生命週期
在一個類編譯完成之後,下一步就需要開始使用類,如果要使用一個類,肯定離不開JVM。在程式執行中JVM通過裝載,連結,初始化這3個步驟完成。
類的裝載是通過類載入器完成的,載入器將.class檔案的二進位制檔案裝入JVM的方法區,並且在堆區建立描述這個類的java.lang.Class物件。用來封裝資料。 但是同一個類只會被類裝載器裝載以前連結就是把二進位制資料組裝為可以執行的狀態。
連結分為校驗,準備,解析這3個階段
校驗一般用來確認此二進位制檔案是否適合當前的JVM(版本),
準備就是為靜態成員分配記憶體空間,。並設定預設值
解析指的是轉換常量池中的程式碼作為直接引用的過程,直到所有的符號引用都可以被執行程式使用(建立完整的對應關係)
完成之後,型別也就完成了初始化,初始化之後類的物件就可以正常使用了,直到一個物件不再使用之後,將被垃圾回收。釋放空間。
當沒有任何引用指向Class物件時就會被解除安裝,結束類的生命週期 。

14、將反射用於工廠模式
來看看如果不用反射的時候的工廠模式吧:

interface fruit{
	public abstract void eat();
}
 
class Apple implements fruit{
	public void eat(){
		System.out.println("Apple");
	}
}
 
class Orange implements fruit{
	public void eat(){
		System.out.println("Orange");
	}
}
 
// 構造工廠類
// 也就是說以後如果我們在新增其他的例項的時候只需要修改工廠類就行了
class Factory{
	public static fruit getInstance(String fruitName){
		fruit f=null;
		if("Apple".equals(fruitName)){
			f=new Apple();
		}
		if("Orange".equals(fruitName)){
			f=new Orange();
		}
		return f;
	}
}
class hello{
	public static void main(String[] a){
		fruit f=Factory.getInstance("Orange");
		f.eat();
	}
 
}

這樣,當我們在新增一個子類的時候,就需要修改工廠類了。如果我們新增太多的子類的時候,改的就會很多。
現在我們看看利用反射機制:
package Reflect;
 
interface fruit{
	public abstract void eat();
}
 
class Apple implements fruit{
	public void eat(){
		System.out.println("Apple");
	}
}
 
class Orange implements fruit{
	public void eat(){
		System.out.println("Orange");
	}
}
 
class Factory{
	public static fruit getInstance(String ClassName){
		fruit f=null;
		try{
			f=(fruit)Class.forName(ClassName).newInstance();
		}catch (Exception e) {
			e.printStackTrace();
		}
		return f;
	}
}
class hello{
	public static void main(String[] a){
		fruit f=Factory.getInstance("Reflect.Apple");
		if(f!=null){
			f.eat();
		}
	}
}
現在就算我們新增任意多個子類的時候,工廠類就不需要修改。
上面的程式碼雖然可以通過反射取得介面的例項,但是需要傳入完整的包和類名。而且使用者也無法知道一個介面有多少個可以使用的子類,所以我們通過屬性檔案的形式配置所需要的子類。

下面我們來看看: 結合屬性檔案的工廠模式

首先建立一個fruit.properties的資原始檔,
內容為:
apple=Reflect.Apple
orange=Reflect.Orange
然後編寫主類程式碼:
package Reflect;

import java.io.*;
import java.util.*;
 
interface fruit{
	public abstract void eat();
}
 
class Apple implements fruit{
	public void eat(){
		System.out.println("Apple");
	}
}
 
class Orange implements fruit{
	public void eat(){
		System.out.println("Orange");
	}
}
 
//操作屬性檔案類
class init{
	public static Properties getPro() throws FileNotFoundException, IOException{
		Properties pro=new Properties();
		File f=new File("fruit.properties");
		if(f.exists()){
			pro.load(new FileInputStream(f));
		}else{
			pro.setProperty("apple", "Reflect.Apple");
			pro.setProperty("orange", "Reflect.Orange");
			pro.store(new FileOutputStream(f), "FRUIT CLASS");
		}
		return pro;
	}
}
 
class Factory{
	public static fruit getInstance(String ClassName){
		fruit f=null;
		try{
			f=(fruit)Class.forName(ClassName).newInstance();
		}catch (Exception e) {
			e.printStackTrace();
		}
		return f;
	}
}
class hello{
	public static void main(String[] a) throws FileNotFoundException, IOException{
		Properties pro=init.getPro();
		fruit f=Factory.getInstance(pro.getProperty("apple"));
		if(f!=null){
			f.eat();
		}
	}
}
【執行結果】:Apple

===========================================
實際專案中的應用:
利用java的反射機制,給兩個不同的物件的屬性賦值,主要是兩個有相同屬性的物件,類似於entity bean 和 VO 這樣的POJO
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import javax.persistence.Id;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * <轉換物件工具>
 * <功能詳細描述>
 * @see  [相關類/方法]
 * @since  [產品/模組版本]
 */
public class ConvertObjectUtil
{
	// log
	private static Log log = LogFactory.getLog(ConvertObjectUtil.class);
	
	/**
	 * <兩個屬性相同的物件,把源物件的屬性值動態賦給目標物件>
	 * <功能詳細描述>
	 * @param srcClass 源型別
	 * @param srcObject 源物件
	 * @param destObject 目標物件
	 * @return 轉換後的目標物件
	 * @see [類、類#方法、類#成員]
	 */
	public static Object convert(Class<?> srcClass, Object srcObject, Object destObject)
	{
		Field[] srcFields = srcClass.getDeclaredFields();
		
		int fieldCount = srcFields.length;
	 
		log.info("src class has :" + fieldCount + " fields");
		for (int i = 0; i < fieldCount; i++)
		{
			// serialVersionUID和自增長的ID除外
			if (srcFields[i].getName().equals("serialVersionUID"))
			{
				continue;
			}
			
			if (srcFields[i].getAnnotation(Id.class) != null)
			{
				continue;
			}
			
			try
			{
				// 利用源物件的get方法和目標物件的set方法,來給目標物件賦值
				Method srcMethod = srcObject.getClass().getMethod("get" + uppercaseFirst(srcFields[i].getName()));
				Object srcValue = srcMethod.invoke(srcObject);
				
				Method destMethod =
					destObject.getClass().getMethod("set" + uppercaseFirst(srcFields[i].getName()),
						srcFields[i].getType());
				destMethod.invoke(destObject, srcValue);
				
			}
			catch (Exception e)
			{
				// TODO Auto-generated catch block
				log.error(e);
			}
		}
		
		return destObject;
	}
	
	/**
	 * <首字母大寫>
	 * <功能詳細描述>
	 * @param name
	 * @return
	 * @see [類、類#方法、類#成員]
	 */
	private static String uppercaseFirst(String name)
	{
		return name.substring(0, 1).toUpperCase() + name.substring(1);
	}
	
}


上面詳細的介紹了Java反射各種用法,使用它能夠使我們的程式碼更加靈活,但它也有它缺點,就是運用它會使我們的軟體的效能降低,複雜度增加,不過現在java對反射也在不斷優化提高,我們可以放心的使用。

如果你感覺本文對你有幫助,你可以繼續關注我的部落格,我會一步一步把框架實現。

這個路還很長很長,非常希望能和大家一起交流,共同學習和進步。
大家看過後覺得有啟發的話可以頂一下這篇文章,讓更多的朋友有機會看到它。也希望大家可以多留言來和我探討框架相關的問題和知識。
最後,謝謝大家的支援!~~~