实现的程序描述:
    通过网络传输多个序列化的类, 不直接用ObjectOutputStream,要对它进一步
的封装,需重写annotate()方法,我想问一下,这个方法如何使用,是什么意思?\
当传输到另一台机器时,需利用ClassLoader类进行动态加载.
    这里面好多问题不懂,希望各位提供一些资料,最好有一些实例说明.
    手头资料不多,不知从何看起,望大家指点!

解决方案 »

  1.   

    首先来说,如果序列化的对象的类的类文件在传输的另一端,我们姑且叫它客户端,存在,那么是不需要再人为地用什么ClassLoader来动态载入类的,也就是说客户端这时可以直接对这个网络传输的流反序列化的。
    因为每个JVM的类实现机制不同,所以序列化一个对象时,并未将一个这个对象的类的相应的对象(假设序列化对象是java.io.File的一个对象,这里所谓的对象的类的相应的对象就是Class.forName("java.io.File")的返回值)写入序列化流,因为一个JVM可能不能对另外一个JVM的Class对象反序列化。但你会发现一个奇怪的现象,就是java.lang.Class类事实上是实现了java.io.Serializable接口的,也就是说一个Class是可以被序列化的。是的,是可以序列化,但序列化一个Class对象事实上是序列化的这个Class对象相应的java.io.ObjectStreamClass对象。反序列化这个Class对象时,缺省时会在本地classpath中查找这个Class对象相应的类的sourceCode,比如说查找java/io/File.class文件,如果找到了sourceCode,则利用这个sourceCode来生成相应的类的对象。
    所以序列化一个对象,是先把这个对象的类相应的ObjectStreamClass对象序列化到流中。然后再写入这上对象的内容。
    反序列化时,如果在本地找不到这个对象的类的sourceCode,则序列化就会失败。但是我们可以通过覆盖ObjectOutputStream.annotateClass和ObjectInputStream.resolveClass来实现从服务器将类的sourceCode传到客户端(在annotateClass方法中,通过传入的类对象,调用classObj.getProtectionDomain().getCodeSource().getLocation().openStream();可以得到类的sourceCode输入流,将这个流写入到输出流),然后在客户端在方法ObjectInputStream.resolveClass中读取到这个sourceCode,并运用ClassLoader来载入这个类。
    请参见ObjectOutputStream和ObjectInputStream的文档。
      

  2.   

    哦,不好意思,昨天写错错了。sourceCode应该是codeSource,好久不用了,忘记了。
    还有那个获取codeSource的代码也错了。丢
    写个例子:
    package whodsow.io;public interface Person
    {
       public String getName();
       public int getAge();
    }这个接口在客户端的classpath中也应该存在。即这个接口可以让JVM用缺省的方法载入。package whodsow.io;
    import java.io.Serializable;public class Student implements Serializable
    {
       private String name;
       private int age;
       
       public Student(String name, int age)
       {
          this.name = name;
          this.age = age;
       }
       
       public String getName()
       {
          return name;
       }
       
       public int getAge()
       {
          return age;
       }
    }//自定义一个序列化类
    package whodsow.io;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.ObjectOutputStream;
    import java.io.OutputStream;/**
     * 
     * @author 胡洲
     */
    public static class MyObjectOutputStream extends ObjectOutputStream
    {
       public MyObjectOutputStream(OutputStream os)throws IOException
       {
          super(os);
       }   protected void annotateClass(Class c)throws IOException
       {
          if(c == Student.class)
          {
             //计算类的codeSource文件,这里的计算结果是相对于一个classpath
             //的相对路径
             String relativeFile
                   = c.getName().replace('.', File.separatorChar)
                   + ".class";
             
             //找一个类装载器来获取这个codeSource的输入流
             ClassLoader cl = Thread.currentThread().getContextClassLoader();
             InputStream is = cl.getResourceAsStream(relativeFile);
             byte[] bs = is.available();
             is.read(bs);         //将Student.class文件的内容写入到输出流中,这里这个输出流,也是序列化对象时
             //底层的输出流
             this.writeObject(bs);
          }
       }
    }//反序列化类
    package whodsow.io;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectStreamClass;/**
     * 
     * @author 胡洲
     */
    public class MyObjectInputStream extends ObjectInputStream
    {
       public MyObjectInputStream(InputStream is)throws IOException
       {
          super(is);
       }   protected Class resolveClass(ObjectStreamClass osc)
             throws IOException, ClassNotFoundException
       {
          String name = osc.getName();
          if(name.startsWith("whodsow.io."))
          {
             System.out.println("resolve class: " + name);
             byte[] codeSource = (byte[])this.readObject();
             return MyClassLoader.loadClass(name, codeSource);
          }
          else
          {
             return super.resolveClass(osc);
          }
       }
    }//类装载器
    package whodsow.io;/**
     * 
     * @author 胡洲
     */
    public class MyClassLoader extends ClassLoader
    {
       private MyClassLoader()
       {
          super(Thread.currentThread().getContextClassLoader());
       }   public static Class loadClass(String name, byte[] codeSource)
       {
          Class c
                = new MyClassLoader().defineClass(name, codeSource, 0,
                      codeSource.length);
          System.out.println("load class: " + c.getName() + " over...");
          return c;
       }
    }//test类
    package whodsow.io;
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;/**
     * 
     * @author 胡洲
     */
    public class Test 
    {
       public static void main(String[] args)
       {
          try
          {
             Person p = new Student("whodsow", 24);
             ByteArrayOutputStream buffer = new ByteArrayOutputStream();
             ObjectOutputStream oos = new MyObjectOutputStream(buffer);
             oos.writeObject(p);
             oos.close();
             
             InputStream is = new ByteArrayInputStream(buffer.toByteArray());
             ObjectInputStream ois = new MyObjectInputStream(is);
             p = (Person)ois.readObject();
             ois.close();
             System.out.println(p.getName() + " " + p.getAge());
          }
          catch (IOException e)
          {
             e.printStackTrace();
          }
          catch (ClassNotFoundException e)
          {
             e.printStackTrace();
          }
       }
    }