iT邦幫忙

1

java readobject的問題

大家好,由於小弟最近才剛java懇請各位專家幫幫忙,我在寫一個進銷貨系統,主要是有一個叫做Cproduct的class還有extends的Cthing類別,建立一個物件陣列class Cproduct[]=new Cproduct[100];然後我把這個物件陣列利用objectoutputstream存到外部的txt檔,現在想要把這個物件陣列從外部txt檔讀入,並存入陣列要怎麼作??因為這個陣列有存入父類別class還有他extends的子類別class。。。
以下是程式碼(有錯!):
public class JavaApplication16 {

/**
 * @param args the command line arguments
 */
public static void main(String[] args) throws IOException, ClassNotFoundException {
    Scanner sc = new Scanner(System.in);
    Cproduct obj[] = new Cproduct[100];
    int choise, i = 0;
    int item[] = new int[100];
    String tempstr;
    int tempid, tempnum;
    for (i = 0; i < 100; i++) {
        System.out.print("1.商品1 2.商品2 3.離開:");
        choise = sc.nextInt();
        if (choise == 1) {
            System.out.print("name:");
            item[i] = 1;
            tempstr = sc.next();
            System.out.print("id:");
            tempid = sc.nextInt();
            obj[i] = new Cproduct(tempstr, tempid);
        }
        if (choise == 2) {
            System.out.print("name:");
            item[i] = 2;
            tempstr = sc.next();
            System.out.print("id:");
            tempid = sc.nextInt();
            System.out.print("num:");
            tempnum = sc.nextInt();
            obj[i] = new Cthing(tempstr, tempid, tempnum);
        }
        if (choise == 3) {
            break;
        }
    }
    System.out.println("success!");
    Cproduct.show(obj, item, i);
    FileOutputStream fo
            = new FileOutputStream("C:\\Users\\USER\\Desktop\\2266.txt");
    ObjectOutputStream oos = new ObjectOutputStream(fo);
    for (int a = 0; a < obj.length; a++) {
        if (item[a] == 1) {
            oos.writeObject(new Cproduct(obj[a].name, obj[a].id));
        }
        if (item[a] == 2) {
            oos.writeObject(new Cthing(obj[a].name, obj[a].id, ((Cthing) obj[a]).num));
        }
    }
    oos.close();
    fo.close();
    obj = null;
    FileInputStream fi
            = new FileInputStream("C:\\Users\\USER\\Desktop\\2266.txt");
    ObjectInputStream ois = new ObjectInputStream(fi);
    obj = (Cproduct[]) ois.readObject();
    for (int a = 0; a < obj.length; a++) {
        if (obj[a].getClass().isAssignableFrom(Cproduct.class)) {
            System.out.println("obj" + a + ":" + obj[a]);
        } else if (obj[a].getClass().isAssignableFrom(Cthing.class)) {
            System.out.println("obj" + a + ":" + (Cthing) obj[a]);
        }
    }
    ois.close();
    fi.close();
}

}

class Cproduct implements Serializable {

public String name;
public int id;

public Cproduct() {
}

public Cproduct(String a, int b) {
    name = a;
    id = b;
}

public static void show(Cproduct arr[], int item[], int i) {
    for (int a = 0; a < i; a++) {
        if (item[a] == 1) {
            System.out.println("第一類");
            System.out.println("\t" + "name:" + arr[a].name);
            System.out.println("\t" + "id:" + arr[a].id);
        }
        if (item[a] == 2) {
            System.out.println("第二類");
            System.out.println("\t" + "name:" + arr[a].name);
            System.out.println("\t" + "id:" + arr[a].id);
            System.out.println("\t" + "num:" + ((Cthing) arr[a]).num);
        }
    }
}

public String toString() {
    return (name + "," + id);
}

}

class Cthing extends Cproduct {

public int num;

public Cthing() {
}

public Cthing(String a, int b, int c) {
    super(a, b);
    num = c;
}

public static void show(Cproduct arr[], int i) {
    System.out.println("2");
    System.out.println("name:" + arr[i].name);
    System.out.println("id:" + arr[i].id);
    System.out.println("id:" + ((Cthing) arr[i]).num);
}

public String toString() {
    return (name + "," + id + "," + num);
}

}

0
fysh711426
iT邦新手 4 級 ‧ 2017-11-13 00:20:55

小弟沒有寫過 Java 所以只能給您一點思路,

if (item[a] == 1) {
    oos.writeObject(new Cproduct(obj[a].name, obj[a].id));
}
if (item[a] == 2) {
    oos.writeObject(new Cthing(obj[a].name, obj[a].id, ((Cthing) obj[a]).num));
}
obj = (Cproduct[]) ois.readObject();

這兩個地方,writeObject 分別寫入了兩種類型的物件,但 readObject 卻只用一種去讀,而且是用陣列,這和原來寫入的型態不一樣,所以讀取過程中不會有 Cthing 這個型態的物件被產生,整個陣列都是 Cproduct 型態的物件甚至是讀取失敗 (這裡是我的猜測),在序列化與反序列化過程中應該要使用相同的類別來處理,序列化 write Cproduct[],反序列化 read Cproduct[],兩邊的型態要一樣。

如果真的一定要用兩個類別來代表商品,可以做一個 ViewModel,把欄位最大化,然後多一個 productType 欄位區分商品1或商品2,序列化與反序列化都透過這個 ViewModel,不過如果是我,我不會把商品分成兩個類別,一開始就會把商品類別做成 ViewModel 的形式,以上是小弟我的淺見。
/images/emoticon/emoticon37.gif

0
海綿寶寶
iT邦超人 1 級 ‧ 2017-11-13 09:46:03

一個簡短又清楚的範例,參考看看
How to read and write Java object to a file

1
fillano
iT邦超人 1 級 ‧ 2017-11-13 09:55:00

參考:https://zh.wikipedia.org/wiki/%E9%87%8C%E6%B0%8F%E6%9B%BF%E6%8D%A2%E5%8E%9F%E5%88%99

我想關鍵不是Cproduct跟Cthing之間的問題,單純只是序列化與反序列化過程中寫入跟讀取的型別不一致。所以在寫入的地方把整個迴圈拿掉,取代成:

oos.writeObject(obj);

就可以了。

不過,既然輸入100個物件的過程可以中斷,那就不能用陣列來存,因為陣列中會有null,最好改用ArrayList等來存,不然就在顯示物件資訊的迴圈開頭加一行程式判斷是否為null:

if(obj[a] == null) break;

我想關鍵不是Cproduct跟Cthing之間的問題

不能同意您更多了
/images/emoticon/emoticon10.gif

https://stackoverflow.com/questions/8141440/how-are-constructors-called-during-serialization-and-deserialization
您是對的,在反序列化的過程並不會依賴 (Cproduct[]) 去產生物件,甚至連建構式都不會呼叫,而是用一種更底層的方式還原物件。
一直以為是類似反射的方式產生物件,覺得怎麼不是這樣寫,
ois.readObject(Cproduct[].class);
/images/emoticon/emoticon32.gif

我要發表回答

立即登入回答