上一篇中,通過例子我們知道了如何利用反射機制創建對象,獲得類變量和調用方法等。創建對象的語句是 Class cla = Class.forName(type); Object obj = cla.newInstance(); 這里newInstance()實際上是使用了該類的默認無參構造方法。如果我們要調用其它的構造方法就要稍微復雜一點。比如我們要創建一個StringBuffer對象,用new 操作符應該是StringBuffer br = new StringBuffer("example");用反射機制則要有以下步驟。
首先,獲得StringBuffer類的描述。
Class cla = Class.forName("java.lang.StringBuffer");
其次,要創建參數類型數組Class[] 。
Class[] paraTypes = new Class[1];paraTypes[0]=String.class;
然后,通過cla 和 paraTypes 獲得Constructor 對象。
Constructor constructor = cla.getConstructor(paraTypes);
接著,創建傳入的參數列表Object[]。
Object[] paraLists = new Object[1]; paraLists[0]="color";
最后,得到我們所要得對象。Object obj = constructor.newInstance(paraLists);
如果我們paraTypes及paraLists設為null或長度為0,就可以用上述步驟調用StringBuffer的無參構造方法。類似地,我們可以調用對象中的有參方法。比如我們做如下操作br.insert(4, 'u');用反射機制實現如下。
Class[] paratypes = new Class[]{int.class,char.class};
Method method = cla.getMethod("insert", paratypes);
Object[] paralists = new Object[]{4,'u'};
method.invoke(obj, paralists);
反射機制給予我們運行時才確定對象類型的便利,然而它也有顯著的缺點。
1,代碼笨拙冗長。比如本來一句br.insert(4, 'u');可以解決的問題現在要用到四句。
2,損失了編譯時類型檢查的好處。這使得你要對付更多的異常。
3,性能損失。用反射機制運行的時間更久。
<<Effective Java >>中給出的建議是“普通應用不應在運行時刻以映像方式訪問對象,只是在很有限的情況下使用“。那么在什么地方會用到反射機制呢。已有的較熟悉應用是我們的IDE及一些框架。比如eclipse,編程時ctrl+space彈出的建議就是用到反射機制。比如Spring讀取配置文件后生成對應的對象。還有RPC系統也會用到。對于一般的應用軟件,你可以在工廠方法中用到它。
參考文章:
<Effective Java> 第一版 35條
<侯捷談Java反射機制>
JAVA API
2008年11月20日
2008年11月17日
下面我以顧客買相機為例來說明Java反射機制的應用。例子中涉及的類和接口有:
Camera接口:定義了takePhoto()方法。
Camera01類:一種照相機的類型,實現Camera接口。
Camera02類:另一種照相機的類型,實現Camera接口。
Seller類:賣照相機。
Customer類:買相機,有main方法。
所有類都放在com包里
程序如下:
public interface Camera {
//聲明照相機必須可以拍照
public void takePhoto();
}
public class Camera01 implements Camera {
private final int prefixs =300;//300萬象素
private final double optionZoom=3.5; //3.5倍變焦
public void takePhoto() {
System.out.println("Camera01 has taken a photo");
}
}
類似的有
public class Camera02 implements Camera {
private final int prefixs =400;
private final double optionZoom=5;
public void takePhoto() {
System.out.println("Camera02 has taken a photo");
}
}
顧客出場了
public class Customer {
public static void main(String[] args){
//找到一個售貨員
Seller seller = new Seller();
//向售貨員詢問兩種相機的信息
seller.getDescription("com.Camera01");
seller.getDescription("com.Camera02");
//覺得Camera02比較好,叫售貨員拿來看
Camera camera =(Camera)seller.getCamera("com.Camera02");
//讓售貨員拍張照試一下
seller.testFuction(camera, "takePhoto");
}
}
Seller類通過Java反射機制實現
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Seller {
//向顧客描述商品信息
public void getDescription(String type){
try {
Class cla = Class.forName(type);
//生成一個實例對象,在編譯時我們并不知道obj是什么類型。
Object obj = cla.newInstance();
//獲得type類型所有已定義類變量及方法。
Field[] fileds = cla.getDeclaredFields();
Method[]methods = cla.getDeclaredMethods();
System.out.println("The arguments of this Camera is:");
for(int i=0;i<fileds.length;i++){
fileds[i].setAccessible(true);
//輸出類變量的定義及obj實例中對應的值
System.out.println(fileds[i]+":"+fileds[i].get(obj));
}
System.out.println("The function of this Camera:");
for(int i=0;i<methods.length;i++){
//輸出類中方法的定義
System.out.println(methods[i]);
}
System.out.println();
} catch (Exception e) {
System.out.println("Sorry , no such type");
}
}
//使用商品的某個功能
public void testFuction(Object obj,String function){
try {
Class cla = obj.getClass();
//獲得cla類中定義的無參方法。
Method m = cla.getMethod(function, null);
//調用obj中名為function的無參方法。
m.invoke(obj, null);
} catch (Exception e) {
System.out.println("Sorry , no such function");
}
}
//拿商品給顧客
public Object getCamera(String type){
try {
Class cla = Class.forName(type);
Object obj = cla.newInstance();
return obj;
} catch (Exception e) {
System.out.println("Sorry , no such type");
return null;
}
}
}
程序到此結束,下一篇我將對程序進行分析,并補充一些內容。
Camera接口:定義了takePhoto()方法。
Camera01類:一種照相機的類型,實現Camera接口。
Camera02類:另一種照相機的類型,實現Camera接口。
Seller類:賣照相機。
Customer類:買相機,有main方法。
所有類都放在com包里
程序如下:
public interface Camera {
//聲明照相機必須可以拍照
public void takePhoto();
}
public class Camera01 implements Camera {
private final int prefixs =300;//300萬象素
private final double optionZoom=3.5; //3.5倍變焦
public void takePhoto() {
System.out.println("Camera01 has taken a photo");
}
}
類似的有
public class Camera02 implements Camera {
private final int prefixs =400;
private final double optionZoom=5;
public void takePhoto() {
System.out.println("Camera02 has taken a photo");
}
}
顧客出場了
public class Customer {
public static void main(String[] args){
//找到一個售貨員
Seller seller = new Seller();
//向售貨員詢問兩種相機的信息
seller.getDescription("com.Camera01");
seller.getDescription("com.Camera02");
//覺得Camera02比較好,叫售貨員拿來看
Camera camera =(Camera)seller.getCamera("com.Camera02");
//讓售貨員拍張照試一下
seller.testFuction(camera, "takePhoto");
}
}
Seller類通過Java反射機制實現
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Seller {
//向顧客描述商品信息
public void getDescription(String type){
try {
Class cla = Class.forName(type);
//生成一個實例對象,在編譯時我們并不知道obj是什么類型。
Object obj = cla.newInstance();
//獲得type類型所有已定義類變量及方法。
Field[] fileds = cla.getDeclaredFields();
Method[]methods = cla.getDeclaredMethods();
System.out.println("The arguments of this Camera is:");
for(int i=0;i<fileds.length;i++){
fileds[i].setAccessible(true);
//輸出類變量的定義及obj實例中對應的值
System.out.println(fileds[i]+":"+fileds[i].get(obj));
}
System.out.println("The function of this Camera:");
for(int i=0;i<methods.length;i++){
//輸出類中方法的定義
System.out.println(methods[i]);
}
System.out.println();
} catch (Exception e) {
System.out.println("Sorry , no such type");
}
}
//使用商品的某個功能
public void testFuction(Object obj,String function){
try {
Class cla = obj.getClass();
//獲得cla類中定義的無參方法。
Method m = cla.getMethod(function, null);
//調用obj中名為function的無參方法。
m.invoke(obj, null);
} catch (Exception e) {
System.out.println("Sorry , no such function");
}
}
//拿商品給顧客
public Object getCamera(String type){
try {
Class cla = Class.forName(type);
Object obj = cla.newInstance();
return obj;
} catch (Exception e) {
System.out.println("Sorry , no such type");
return null;
}
}
}
程序到此結束,下一篇我將對程序進行分析,并補充一些內容。
摘要: Java 反射機制是指Java程序可以在執行期載入,探知,使用編譯期間完全未知的classes 閱讀全文
2008年11月10日
EJB中的sessionbean可以對外提供Remote接口供遠程客戶端調用.其客戶端可以是servlet,java application,或EJB.下面我跟大家分享如何在java application中遠程調用session bean.我的配置環境如下。
Sessionbean:運行在websphere v6.0 中,其jndi名為"Hello"
Java Application: 使用eclipse IDE 創建。
首先,要對eclipse進行配置。必須與服務器 websphere使用相同的JRE.在eclipse菜單欄中選擇Window,Preferences,在彈出窗口的左邊選擇Java,Installed JREs.默認地,右邊窗口現示安裝了jre1.5.0.0_07(具體版本可能有所不同)。我們需要把它換成websphere的JRE.把jre1.5.0.0_07前面的勾去掉,點擊add.在彈出窗口的第三行:JRE home directory 選擇Browse....JRE的路徑為C:\Program Files\IBM\Rational\SDP\6.0\runtimes\base_v6\java\jre。如果你沒有安裝RAD,就需要到網上下載一個JRE.一直點擊OK退回eclipse主界面。
其次,要向工程添加必要的JAR。右擊工程,選擇Properties-Java Build Path-Add Extenal JARs。添加如下的Jar:wssec.jar,naming.jar,namingclient.jar,sas.jar,ecutils.jar,websphere.jar。這些jar都可以在C:\Program Fires\Rational\SDP\6.0\runtimes\base_v6\lib目錄下找到。
接著我門要把sessionbean‘Hello’的home和remote接口的.class文件拷被到eclipse的工程中,使得我們在工程中可以引用它。
具體程序如下:
public class Test{
public static void main(String[] args) throws NamingException,
RemoteException, CreateException {
Properties properties = System.getProperties();
//因為客戶端和sessionbean不是運行在同一服務器上,需要對properties進行配置。
//如果不是在同一臺電腦上運行localhost需改為服務器的ip地址或主機名
//900是服務器端口,默認值可能是900或2809
properties.put(Context.PROVIDER_URL, "iiop://localhost:900");
properties.put(Context.INITIAL_CONTEXT_FACTORY,
"com.ibm.websphere.naming.WsnInitialContextFactory");
Context ctx = new InitialContext(properties);
Object obj = ctx.lookup("Hello");
HelloHome ejbHome = (HelloHome) javax.rmi.PortableRemoteObject
.narrow(obj, HelloHome.class);
Hello hello= ejbHome.create();
//現在我們取得了所需要的hello對象
}
}
Sessionbean:運行在websphere v6.0 中,其jndi名為"Hello"
Java Application: 使用eclipse IDE 創建。
首先,要對eclipse進行配置。必須與服務器 websphere使用相同的JRE.在eclipse菜單欄中選擇Window,Preferences,在彈出窗口的左邊選擇Java,Installed JREs.默認地,右邊窗口現示安裝了jre1.5.0.0_07(具體版本可能有所不同)。我們需要把它換成websphere的JRE.把jre1.5.0.0_07前面的勾去掉,點擊add.在彈出窗口的第三行:JRE home directory 選擇Browse....JRE的路徑為C:\Program Files\IBM\Rational\SDP\6.0\runtimes\base_v6\java\jre。如果你沒有安裝RAD,就需要到網上下載一個JRE.一直點擊OK退回eclipse主界面。
其次,要向工程添加必要的JAR。右擊工程,選擇Properties-Java Build Path-Add Extenal JARs。添加如下的Jar:wssec.jar,naming.jar,namingclient.jar,sas.jar,ecutils.jar,websphere.jar。這些jar都可以在C:\Program Fires\Rational\SDP\6.0\runtimes\base_v6\lib目錄下找到。
接著我門要把sessionbean‘Hello’的home和remote接口的.class文件拷被到eclipse的工程中,使得我們在工程中可以引用它。
具體程序如下:
public class Test{
public static void main(String[] args) throws NamingException,
RemoteException, CreateException {
Properties properties = System.getProperties();
//因為客戶端和sessionbean不是運行在同一服務器上,需要對properties進行配置。
//如果不是在同一臺電腦上運行localhost需改為服務器的ip地址或主機名
//900是服務器端口,默認值可能是900或2809
properties.put(Context.PROVIDER_URL, "iiop://localhost:900");
properties.put(Context.INITIAL_CONTEXT_FACTORY,
"com.ibm.websphere.naming.WsnInitialContextFactory");
Context ctx = new InitialContext(properties);
Object obj = ctx.lookup("Hello");
HelloHome ejbHome = (HelloHome) javax.rmi.PortableRemoteObject
.narrow(obj, HelloHome.class);
Hello hello= ejbHome.create();
//現在我們取得了所需要的hello對象
}
}