2008年11月10日

  上一篇中,通过例子我们知道了如何利用反射机制创建对象,获得类变量和调用方法等。创建对象的语句是  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
                                                                                                                           

posted @ 2008-11-20 15:27 JFire 阅读(1420) | 评论 (0)编辑 收藏
 
  下面我以顾客买相机为例来说明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;
  } 
 }
}
  程序到此结束,下一篇我将对程序进行分析,并补充一些内容。
posted @ 2008-11-17 14:30 JFire 阅读(1821) | 评论 (2)编辑 收藏
 
     摘要: Java 反射机制是指Java程序可以在执行期载入,探知,使用编译期间完全未知的classes  阅读全文
posted @ 2008-11-17 13:30 JFire 阅读(1593) | 评论 (0)编辑 收藏
 
 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对象
         }
}  
posted @ 2008-11-10 09:07 JFire 阅读(1936) | 评论 (0)编辑 收藏