大家好,由於小弟最近才剛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);
}
}
小弟沒有寫過 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 的形式,以上是小弟我的淺見。
一個簡短又清楚的範例,參考看看
How to read and write Java object to a file
參考: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之間的問題
不能同意您更多了
https://stackoverflow.com/questions/8141440/how-are-constructors-called-during-serialization-and-deserialization
您是對的,在反序列化的過程並不會依賴 (Cproduct[])
去產生物件,甚至連建構式都不會呼叫,而是用一種更底層的方式還原物件。
一直以為是類似反射的方式產生物件,覺得怎麼不是這樣寫,
ois.readObject(Cproduct[].class);