1

更新

感谢大家的大力帮助,在这里我必须添加一个关于异常的可能原因:

如果您在域类中添加readObject()writeObject()(如下面的类大学),并且您必须ObjectOutputStream.writeObject()在 main() 方法中调用方法,那么请确保:

---不要将ObjectOutputStream.close()方法放在域类中。它将导致异常,因为由于该对象已关闭,因此对该对象进行操作是非法的(程序如何读取文件或在文件已关闭后关闭文件?)。

我知道这是一个小问题,但调试起来非常微妙,因为异常不会说明任何事情。因此,这是记录在案的一点点。


我尝试实现一个简单的片段来破坏瞬态对象的序列化,即序列化瞬态对象的原始字段,然后通过 ObjectInputStream 反序列化这些原始字段,最后用它们组成一个新对象。场景是这样的:

public class College implements Serializable{
    private static final long serialVersionUID = 1L;

    private String name;
    private transient City city; //transient
    private String zipCode;

    // constructors & getter/setters

private void writeObject(ObjectOutputStream os){
    try {
        os.defaultWriteObject();
        os.writeInt(city.getCode());
        os.writeInt(city.getPopulation());
        os.writeObject(city.getName());
        os.flush();
        os.close(); // update: not good practice, may throw exception.
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

private void readObject(ObjectInputStream os){
    try {
        os.defaultReadObject();
        int code = os.readInt();
        int population = os.readInt();
        String name = (String)os.readObject();
        City theCity = new City(code, name, population);
        System.out.println(theCity.toString());
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    
}
}

这里是城市类

public class City {
    // the primitive & String fields
    private int code;
    private String name;
    private int population;

    // getter/setters

}

这是编写和读取college对象的可爱代码(有点笨拙,抱歉)

public class GeneralTest {

public static void main(String[] args) {
    // TODO Auto-generated method stub
    City city = new City(375, "New York", 380897);
    College college = new College("NYU", city, "10289");
    College readCollege = null;
    City readCity = null;
    
    System.out.println("Before serialization -- City: ["+city.toString()+"], College: ["+college.toString()+"]");
    
    try {
        FileOutputStream fs = new FileOutputStream("college.foo");
        ObjectOutputStream os = new ObjectOutputStream(fs);
        os.writeObject(college);
        os.close();
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    
    try {
        FileInputStream fis = new FileInputStream("college.foo");
        ObjectInputStream ois = new ObjectInputStream(fis);
        readCollege = (College)ois.readObject();

        //get values to compose a city object
        int id = ois.readInt();
        int population = ois.readInt();
        String name = ois.readUTF();
        readCity = new City(id, name, population);
        
        ois.close();
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    
    System.out.println("After serialization -- City: ["+readCity.toString()+"], College: ["+readCollege.toString()+"]");
}

}

然后我得到了这个异常并且readCollegeandreadCity显然是空的:(

java.io.IOException: Write error
    at java.io.FileOutputStream.writeBytes(Native Method)
    at java.io.FileOutputStream.write(FileOutputStream.java:282)
    at java.io.ObjectOutputStream$BlockDataOutputStream.drain(ObjectOutputStream.java:1847)
    at java.io.ObjectOutputStream$BlockDataOutputStream.setBlockDataMode(ObjectOutputStream.java:1756)
    at java.io.ObjectOutputStream.writeNonProxyDesc(ObjectOutputStream.java:1257)
    at java.io.ObjectOutputStream.writeClassDesc(ObjectOutputStream.java:1211)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1395)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
    at java.io.ObjectOutputStream.writeFatalException(ObjectOutputStream.java:1547)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:333)
    at serialized.GeneralTest.main(GeneralTest.java:27)
java.io.EOFException
    at java.io.ObjectInputStream$BlockDataInputStream.readByte(ObjectInputStream.java:2721)
    at java.io.ObjectInputStream$BlockDataInputStream.readUTFChar(ObjectInputStream.java:3113)
    at java.io.ObjectInputStream$BlockDataInputStream.readUTFBody(ObjectInputStream.java:3010)
    at java.io.ObjectInputStream$BlockDataInputStream.readUTF(ObjectInputStream.java:2819)
    at java.io.ObjectInputStream.readUTF(ObjectInputStream.java:1050)
    at serialized.College.readObject(College.java:70)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:969)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1848)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
    at serialized.GeneralTest.main(GeneralTest.java:40)
java.io.EOFException
    at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2553)
    at java.io.ObjectInputStream.skipCustomData(ObjectInputStream.java:1899)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1873)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
    at serialized.GeneralTest.main(GeneralTest.java:40)
Exception in thread "main" java.lang.NullPointerException
    at serialized.GeneralTest.main(GeneralTest.java:52)

有任何想法吗?提前致谢。

4

3 回答 3

1

这是您输出的代码部分

    FileOutputStream fs = new FileOutputStream("college.foo");
    ObjectOutputStream os = new ObjectOutputStream(fs);
    os.writeObject(college);
    os.close();

您创建流,编写college对象,然后关闭它。

这是您正在阅读的部分:

    FileInputStream fis = new FileInputStream("college.foo");
    ObjectInputStream ois = new ObjectInputStream(fis);
    readCollege = (College)ois.readObject();

至此,您已经阅读了您所写的所有内容。你以前写过大学,现在你读了。

然后你去这样做:

    //get values to compose a city object
    int id = ois.readInt();
    int population = ois.readInt();
    String name = ois.readUTF();
    readCity = new City(id, name, population);

你怎么能指望在这里读到任何东西?你只写了college。然后你读college回(进入readCollege参考。然后你试图再读两个整数和一个字符串?这些数据应该从哪里来?没有什么可读的了。

于 2012-11-01T15:14:06.577 回答
1

将您的 ois.readUTF() 替换为 ois.readObject() 并将其转换为字符串。

String name = (String) ois.readObject();

没有编译/尝试过...

于 2012-11-01T15:14:16.220 回答
1

当您执行此行时:

readCollege = (College)ois.readObject();

之后的流中就没有任何东西了。

因此,您未来阅读同一流的尝试会在逻辑上抛出java.io.EOFException:(此外,请注意替换readUTF()by readObject()

//get values to compose a city object
        int id = ois.readInt();   // there's nothing more !! throws exception!
        int zip = ois.readInt();
        String name = (String)ois.readObject();

实际上,您在写入流时没有添加自定义值。

因此,一个解决方案示例,添加专门用于添加所需元素的三行City

try {
        FileOutputStream fs = new FileOutputStream("college.foo");
        ObjectOutputStream os = new ObjectOutputStream(fs);
        os.writeObject(college);
        os.writeInt(1); //adding the id !
        os.writeInt(75019); //adding the zip !
        os.writeObject("name"); //adding the name !
        os.close();
    } catch (IOException e) {
        e.printStackTrace();
    }

当然,读取字段的顺序必须与写入期间的顺序相同

评论后更新:

事实上,您已经通过您的方法读取了类City内的自定义值,因此这些行是无用的:CollegereadObject()

int id = ois.readInt();
int population = ois.readInt();
String name = (String)ois.readObject();   // remove them all

为什么 ???因为正如我之前解释的那样,他们只是抛出了java.io.EOFException因为没有更多可阅读的内容。

这是一个有效的全局代码:

class College implements Serializable {
    private static final long serialVersionUID = 1L;

    private String name;
    private transient City city; //transient
    private String zipCode;

    College(String name, City city, String zipCode) {
        this.name = name;
        this.city = city;
        this.zipCode = zipCode;
    }

    private void readObject(ObjectInputStream os) {
        try {
            os.defaultReadObject();
            int code = os.readInt();
            int population = os.readInt();
            String name = (String) os.readObject();
            this.city = new City(code, name, population);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private void writeObject(ObjectOutputStream os) {
        try {
            os.defaultWriteObject();
            os.writeInt(1);
            os.writeInt(200);
            os.writeObject("thename");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public City getCity() {
        return city;
    }

    public void setCity(City city) {
        this.city = city;
    }

    public String getZipCode() {
        return zipCode;
    }

    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }
}

class City {
    // the primitive & String fields
    private int code;
    private String name;
    private int population;

    City(int code, String name, int population) {
        this.code = code;
        this.name = name;
        this.population = population;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }

    // getter/setters
}

public class Launcher {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        City city = new City(375, "New York", 380897);
        College college = new College("NYU", city, "10289");
        College readCollege = null;
        City readCity = null;

        System.out.println("Before serialization -- City: [" + city.toString() + "], College: [" + college.toString() + "]");

        try {
            FileOutputStream fs = new FileOutputStream("college.foo");
            ObjectOutputStream os = new ObjectOutputStream(fs);
            os.writeObject(college);
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            FileInputStream fis = new FileInputStream("college.foo");
            ObjectInputStream ois = new ObjectInputStream(fis);
            readCollege = (College) ois.readObject();
            readCity = readCollege.getCity();

            ois.close();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("After serialization -- City: [" + readCity.toString() + "], College: [" + readCollege.toString() + "]");
    }

}
于 2012-11-01T15:24:01.900 回答