Почему объект не меняется, когда я отправляю его через метод writeObject?

Я делаю сетевую программу с Java. Как следует из заголовка, объект, который сервер пытается отправить, изменяется в клиенте, который его получает. Я пытаюсь изменить объект, который существует в клиенте, прежде чем я получу новый с сервера. Вот мои коды. Первый — Server.sendIdea, а второй — Client.rcvIdea.

void sendIdea(Idea _idea) throws IOException {
    objectOS.flush();
    Idea idea = _idea;
//when I look into 'idea' it's fine
    objectOS.writeObject(idea);
}

..

Idea rcvIdea(int _ideaCode) throws ClassNotFoundException, IOException {
    objectOS.writeObject("sendIdea");
    objectOS.writeObject(_ideaCode);
    Idea returnValue = (Idea) objectIS.readObject();
//when I look into 'returnValue', it is not the one 'sendIdea' has sent.
    return returnValue;
}

Как видите, sendIdea(Idea _idea) отправляет объект из класса Idea с помощью метода writeObject. И rcvIdea() получает объект, используя метод readObject(). (Я уверен, что вам не нужно подробно знать о классе Idea). Клиент фактически получил несколько Ideas при запуске этой программы этим методом, и проблем не было. Но когда я пытаюсь получить этим методом тот же, но немного измененный объект Idea, в классе Client объект не меняется, в отличие от класса Server, где объект, который будет отправлен методом sendIdea, изменяется корректно. Я пытался около 5 часов, чтобы решить эту проблему. Я проверил все коды построчно и ничего не нашел. Я почти уверен, что у метода writeObject или readObject есть проблема. Я пытался objectOS.flush() избавиться от ручья и многих других испытаний. Я надеюсь, что я могу найти проблему. Ниже приведены некоторые коды в моей программе

Пакет client.class ideaOcean;

import java.awt.HeadlessException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;

import javax.swing.JOptionPane;

import data.Idea;
import data.Opinion;
import data.Profile;

public class Client {
Socket socket;
OutputStream os;
ObjectOutputStream objectOS;
InputStream is;
ObjectInputStream objectIS;
MainWindow mainWindow;

int idCode;
String email, password;
Profile myProfile;
ArrayList<Idea> myIdeas;
ArrayList<Opinion> myOpinions;
ArrayList<Integer> newIdeasCodes, hotIdeasCodes;
ArrayList<Idea> newIdeas, hotIdeas;

String command;

static final String SERVER_IP = "127.0.0.1";// 
static final int SERVER_PORT_NUM = 5000;

public static void main(String[] args) {
    Client client = new Client();
    client.mainWindow = new MainWindow();

    client.mainWindow.setVisible(true);

    client.mainWindow.showLoginPg();
    try {
        while (!client.loginCheck()) {// login
            continue;
        }
    } catch (HeadlessException | NumberFormatException | ClassNotFoundException | IOException e) {
        e.printStackTrace();
    }
    System.out.println("[login complete]");

    try {
        client.myProfile = client.rcvProfile(client.idCode);// get myProfile
        int i;
        for (i = 0; i < client.myProfile.myIdeaCode.size(); i++) {
            client.myIdeas.add(client.rcvIdea(client.myProfile.myIdeaCode.get(i)));
        }
        for (i = 0; i < client.myProfile.myOpinionCode.size(); i++) {
            client.myOpinions.add(client.rcvOpinion(client.myProfile.myOpinionCode.get(i)));
        }
        // ***************************
    } catch (ClassNotFoundException | IOException e1) {
        e1.printStackTrace();
    }

    try {
        client.rcvNewIdeas(12);
        client.mainWindow.newOcean.floatingIdeas = client.newIdeas;
        client.mainWindow.newOcean.arrangeFloatingPanels();

        client.rcvHotIdeas(12);
        client.mainWindow.hotOcean.floatingIdeas = client.hotIdeas;
        client.mainWindow.hotOcean.arrangeFloatingPanels();
    } catch (ClassNotFoundException | IOException e) {
        e.printStackTrace();
    }

    client.mainWindow.setMyPg(client.myProfile, client.myIdeas, client.myOpinions);
    client.mainWindow.showMainPg();

    client.start();
}

public Client() {
    try {
        socket = new Socket(SERVER_IP, SERVER_PORT_NUM);

        System.out.println("Connected to Server!");

        os = socket.getOutputStream();
        objectOS = new ObjectOutputStream(os);
        is = socket.getInputStream();
        objectIS = new ObjectInputStream(is);

        myIdeas = new ArrayList<>();
        myOpinions = new ArrayList<>();
        newIdeasCodes = new ArrayList<>();
        hotIdeasCodes = new ArrayList<>();
        newIdeas = new ArrayList<>();
        hotIdeas = new ArrayList<>();

    } catch (UnknownHostException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

void start() {
    while (true) {
        try {
            if (mainWindow.newBtnClicked) {
                rcvNewIdeas(12);
                mainWindow.newOcean.floatingIdeas = newIdeas;
                mainWindow.newOcean.arrangeFloatingPanels();
                mainWindow.newBtnClicked = false;
            } else if (mainWindow.hotBtnClicked) {
                rcvHotIdeas(12);
                mainWindow.hotOcean.floatingIdeas = hotIdeas;
                mainWindow.hotOcean.arrangeFloatingPanels();
                mainWindow.hotBtnClicked = false;
            } else if (mainWindow.newOcean.detailBtnClicked) {

                updateIdeaDetailFrame(mainWindow.newOcean.clickedIdea);
                mainWindow.newOcean.detailBtnClicked = false;

            } else if (mainWindow.hotOcean.detailBtnClicked) {

                updateIdeaDetailFrame(mainWindow.hotOcean.clickedIdea);
                mainWindow.hotOcean.detailBtnClicked = false;

            } else if (mainWindow.ideaDetailFrame.saveOpinionBtnClicked) {

                sendOpinion(mainWindow.ideaDetailFrame.newOpinion);
                updateIdeaDetailMainPanel(rcvIdea(mainWindow.ideaDetailFrame.idea.ideaCode));
                mainWindow.ideaDetailFrame.saveOpinionBtnClicked = false;

            } else if (mainWindow.writeIdeaPg.postIdeaBtnClicked) {

                sendIdea(mainWindow.writeIdeaPg.thisIdea);
                mainWindow.writeIdeaPg.postIdeaBtnClicked = false;

            } else if (mainWindow.newOcean.plusBtnClicked) {

                objectOS.writeObject("plusBtnClicked");
                objectOS.writeObject(mainWindow.newOcean.plusMinusClickedIdeaCode);
                mainWindow.newOcean.plusBtnClicked = false;

            } else if (mainWindow.newOcean.minusBtnClicked) {

                objectOS.writeObject("minusBtnClicked");
                objectOS.writeObject(mainWindow.newOcean.plusMinusClickedIdeaCode);
                mainWindow.newOcean.minusBtnClicked = false;

            } else if (mainWindow.hotOcean.plusBtnClicked) {

                objectOS.writeObject("plusBtnClicked");
                objectOS.writeObject(mainWindow.hotOcean.plusMinusClickedIdeaCode);
                mainWindow.hotOcean.plusBtnClicked = false;

            } else if (mainWindow.hotOcean.minusBtnClicked) {

                objectOS.writeObject("minusBtnClicked");
                objectOS.writeObject(mainWindow.hotOcean.plusMinusClickedIdeaCode);
                mainWindow.hotOcean.minusBtnClicked = false;

            } else if (mainWindow.myBtnClicked) {

                mainWindow.setMyPg(myProfile, myIdeas, myOpinions);
                mainWindow.myBtnClicked = false;
            }
        } catch (ClassNotFoundException | IOException e) {
            e.printStackTrace();
        }
    }
}

int i = 0;

Idea rcvIdea(int _ideaCode) throws ClassNotFoundException, IOException {
    objectOS.writeObject("sendIdea");
    objectOS.writeObject(_ideaCode);
    Idea returnValue = (Idea) objectIS.readObject();
    return returnValue;
}

Opinion rcvOpinion(int _opinionCode) throws ClassNotFoundException, IOException {
    objectOS.writeObject("sendOpinion");
    objectOS.writeObject(_opinionCode);
    return (Opinion) objectIS.readObject();
}

Profile rcvProfile(int _idCode) throws IOException, ClassNotFoundException {
    objectOS.writeObject("sendProfile");
    objectOS.writeObject(_idCode);
    return (Profile) objectIS.readObject();
}

void rcvNewIdeasCodes() throws ClassNotFoundException, IOException {
    objectOS.writeObject("sendNewIdeasCodes");
    newIdeasCodes = (ArrayList<Integer>) objectIS.readObject();
}

void rcvHotIdeasCodes() throws IOException, ClassNotFoundException {
    objectOS.writeObject("sendHotIdeasCodes");
    hotIdeasCodes = (ArrayList<Integer>) objectIS.readObject();
}

void rcvNewIdeas(int num) throws ClassNotFoundException, IOException {
    int i;
    rcvNewIdeasCodes();
    newIdeas = new ArrayList<>();
    if (num <= newIdeasCodes.size()) {
        for (i = 0; i < num; i++) {
            newIdeas.add(rcvIdea(newIdeasCodes.get(i)));
        }
    } else {
        for (i = 0; i < newIdeasCodes.size(); i++) {
            newIdeas.add(rcvIdea(newIdeasCodes.get(i)));
        }
    }
}

void rcvHotIdeas(int num) throws ClassNotFoundException, IOException {
    int i;
    rcvHotIdeasCodes();
    hotIdeas = new ArrayList<>();
    if (num <= hotIdeasCodes.size()) {
        for (i = 0; i < num; i++) {
            hotIdeas.add(rcvIdea(hotIdeasCodes.get(i)));
        }
    } else {
        for (i = 0; i < hotIdeasCodes.size(); i++) {
            hotIdeas.add(rcvIdea(hotIdeasCodes.get(i)));
        }
    }
}

void sendIdea(Idea _idea) throws IOException {
    objectOS.writeObject("rcvIdea");
    objectOS.writeObject(_idea);
}

void sendOpinion(Opinion _opinion) throws IOException {
    objectOS.writeObject("rcvOpinion");
    objectOS.writeObject(_opinion);
}

void sendProfile(Profile _profile) throws IOException {
    objectOS.writeObject(_profile);
}

boolean loginCheck() throws HeadlessException, NumberFormatException, IOException, ClassNotFoundException {
    objectOS.writeObject("loginCheck");// send command

    while (!mainWindow.loginBtnClicked) {
        continue;
    }
    mainWindow.loginBtnClicked = false;

    email = mainWindow.emailField.getText().trim();
    password = mainWindow.passwordField.getText().trim();
    objectOS.writeObject(email);
    objectOS.writeObject(password);

    boolean valid;
    valid = (boolean) objectIS.readObject();
    if (valid == false) {
        JOptionPane.showMessageDialog(mainWindow, "ID or Password is not correct");
        mainWindow.emailField.setText("");
        mainWindow.passwordField.setText("");
        return false;
    } else if (valid == true) {
        idCode = (int) objectIS.readObject();
        return true;
    } else {
        return false;
    }
}

void updateIdeaDetailMainPanel(Idea clickedIdea) throws ClassNotFoundException, IOException {
    ArrayList<Opinion> opinions = new ArrayList<>();
    for (int j = 0; j < clickedIdea.opinionCode.size(); j++) {
        opinions.add(rcvOpinion(clickedIdea.opinionCode.get(j)));
    }
    mainWindow.ideaDetailFrame.updateMainPanel(opinions);
}

void updateIdeaDetailFrame(Idea clickedIdea) throws ClassNotFoundException, IOException {
    ArrayList<Opinion> opinions = new ArrayList<>();
    for (int j = 0; j < clickedIdea.opinionCode.size(); j++) {
        opinions.add(rcvOpinion(clickedIdea.opinionCode.get(j)));
    }
    mainWindow.ideaDetailFrame = new IdeaDetailFrame(clickedIdea, opinions);
    mainWindow.ideaDetailFrame.setVisible(true);
}
}

Данные пакета Idea.class;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;

public class Idea implements Serializable {

private static final long serialVersionUID = 123123L;
public int idCode;
public int ideaCode;

public int plus = 0, minus = 0;

public String ideaName;
public String oneLineExp;
public String explanation;
public ArrayList<Integer> opinionCode;
public Date date;
public MyCanvas image;

int hotDegree;

public Idea(int _idCode,int _ideaCode, String _ideaName, String _oneLineExp, String _explanation, MyCanvas _image) {
    this(_idCode,_ideaName,_oneLineExp,_explanation,_image);
    ideaCode = _ideaCode;

}

public Idea(int _idCode, String _ideaName, String _oneLineExp, String _explanation, MyCanvas _image) {
    this(_idCode,_ideaName,_oneLineExp,_explanation);
    image = _image;
}

public Idea(int _idCode, String _ideaName, String _oneLineExp, String _explanation){
    idCode = _idCode;
    oneLineExp = new String(_oneLineExp);
    ideaName = new String(_ideaName);
    explanation = new String(_explanation);
    date = new Date();
    opinionCode = new ArrayList<>();
}

public void saveIdea() {
    FileOutputStream fos = null;
    ObjectOutputStream oos = null;

    try {
        fos = new FileOutputStream("Idea.dat");
        oos = new ObjectOutputStream(fos);

        oos.writeObject(this);
    } catch (IOException e1) {
        System.out.println("e1");
    }
}

void addOpinionCode(int _opinion) {
    opinionCode.add(opinionCode.size(), _opinion);
}

public void incPlus() {
    plus++;
}

public void incMinus() {
    minus++;
}

public int setHotDegree() {
    hotDegree = plus - minus + opinionCode.size() * 2;
    return hotDegree;
}

}

Мнение.класс

package data;

import java.io.Serializable;
import java.util.Date;

public class Opinion implements Serializable{
int idCode;
public int opinionCode;//the intrinsic code of this opinion

public int commentedIdeaCode;
public String opinion;
public Date date;
int plus, minus;

public Opinion(int _idCode,int _commentedIdeaCode, String _opinion){
    idCode = _idCode;
    commentedIdeaCode = _commentedIdeaCode;
    opinion = new String(_opinion);
    date = new Date();
    plus = 0;
    minus = 0;
}// Opinion(int _idCode,int _commentedIdeaCode, String _opinion)

public Opinion(int _idCode,int _opinionCode,int _commentedIdeaCode, String _opinion){
    this(_idCode, _commentedIdeaCode, _opinion);
    opinionCode = _opinionCode;
}//Opinion(int _idCode,int _opinionCode,int _commentedIdeaCode, String _opinion)

void incPlus(){
    plus++;
}

void incMinus(){
    minus++;
}
}

person JHKwag    schedule 09.12.2016    source источник
comment
(Я уверен, что вам не нужно подробно знать о классе Idea) -> на самом деле да, мы знаем   -  person JonK    schedule 09.12.2016
comment
Я так понимаю, objectOS и objectIS являются стандартными ObjectInput/OutputStreams? Если это так, маловероятно, что их метод чтения/записи работает неправильно. Он используется огромной кодовой базой во всех видах кода производственного качества. Более вероятно, что детали реализации класса Idea делают экземпляр объекта ObjectInputStream.readObject() неинтуитивным (например, из-за того, что в конструкторе используются статические переменные или что-то еще, что отделяет состояние от сериализованного объекта).   -  person Markus Fischer    schedule 09.12.2016
comment
что ты имеешь в виду под the object does not change? Атрибуты не меняются? equals по-прежнему возвращает true? Вы написали the same but slightly changed object Idea, можете ли вы предоставить MVCE, чтобы показать, как вы меняете и отправляете объект?   -  person jhamon    schedule 09.12.2016
comment
Есть ли в вашем классе Idea конструктор по умолчанию? В примере кода он отсутствует.   -  person Alexander    schedule 09.12.2016
comment
@jhamon Как вы можете видеть в основном методе класса Client, клиентский объект получает множество объектов Idea с сервера, используя метод rcvIdea. Тогда у клиента есть много объектов Idea. Но когда клиент получает объект Idea, который был в клиенте, а теперь немного изменен на сервере, этот объект остается таким же, как и объект в начале.   -  person JHKwag    schedule 09.12.2016
comment
@Alexander Александр Я создал конструктор по умолчанию и снова запустил его, но проблема не решена.   -  person JHKwag    schedule 09.12.2016
comment
Пожалуйста, ответьте на первый вопрос, который я задал в предыдущем комментарии. И я спрашиваю другого: что остается неизменным? Объект Java или содержимое, отображаемое в ideaDetailFrame? Постарайтесь быть более конкретным.   -  person jhamon    schedule 09.12.2016
comment
@MarkusFischer Я согласен с тобой. метод чтения/записи не должен быть неправильным, но я перепробовал множество отладок, но ничего не нашел. Я написал класс идей. Есть ли проблема?   -  person JHKwag    schedule 09.12.2016
comment
@jhamon Вначале opinionCode в объектах Idea имеет размер 3. Затем во время выполнения программы Клиент отправляет новые opinion на сервер, и сервер добавляет целочисленное значение opinionCode этого объекта мнения в ArrayList opinionCode в объекте идеи и отправить объект идеи клиенту еще раз. Этот объект идеи имеет все те же свойства, кроме ArrayList opinionCode, который был изменен сервером. Поэтому я упомянул, что это «то же самое, но немного изменено».   -  person JHKwag    schedule 09.12.2016
comment
@jhamon Затем клиент вызывает updateIdeaDetailMainPanel, и параметр является новым объектом идеи. Но clickedIdea.opinionCode.size() в методе updateIdeaDetailMainPanel все еще совпадает с началом (которое было 3). Я отредактирую свой вопрос, чтобы добавить больше кодов. Пожалуйста, посмотрите   -  person JHKwag    schedule 09.12.2016


Ответы (1)


ObjectOutputStream создает граф всех уже сериализованных объектов и использует ссылки на ранее сериализованные объекты. Поэтому, когда вы сериализуете экземпляр Idea несколько раз, каждый раз после первого записывается ссылка на первую сериализацию вместо полного объекта.

Вы можете использовать ObjectOutputStream.reset() после каждой сериализации. Это отбрасывает граф объектов и заставляет ObjectOutputStream создавать новые сериализации объектов, даже для объектов, которые он видел раньше.

Таким образом, ваш метод sendIdea должен выглядеть так:

void sendIdea(Idea _idea) throws IOException {
    objectOS.flush();
    objectOS.reset();

    Idea idea = _idea;
    objectOS.writeObject(idea);
}

Очень важно, обратите внимание, что после reset() все ссылки на объекты сериализуются заново. Поэтому, если у вас есть сложный граф объектов, вы можете получить дубликаты объектов после десериализации.

Если вы хотите поделиться транзитивными ссылками на объект, который должен сериализоваться несколько раз, вместо этого посмотрите на ObjectOutputStream.writeUnshared().

person Markus Fischer    schedule 12.12.2016