2014-11-30 3 views
1

Я пытаюсь загрузить 2D-массив из файла. Я могу сохранить его, используя этот блок кода:NullPointerException from FileInputStream readObject()

 // Save the array to a file using ObjectOutputStream 
     ObjectOutputStream os; 
     try { 
      os = new ObjectOutputStream(new FileOutputStream("savestate.dat")); 
      os.writeObject(playingField); 
      os.close(); 
     } catch (IOException ex) { 
      ex.printStackTrace(); 
     } 

Я затем попытаться загрузить файл с помощью этого:

 // First, load file using ObjectInputStream 
     ObjectInputStream is = null; 
     try { 
      is = new ObjectInputStream(new FileInputStream("savestate.dat")); 
     } catch (IOException e1) { 
      e1.printStackTrace(); 
     } 

     // Then, read object and cast it as EnhancedMinesweeperTile[][]  
     try { 
      playingField = (EnhancedMinesweeperTile[][]) is.readObject(); 
     } catch (ClassNotFoundException | IOException e1) { 
      e1.printStackTrace(); 
     } 

Но я получаю NullPointerException при попытке загрузить его:

Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException 
at java.awt.Container.updateGraphicsData(Unknown Source) 
at java.awt.Container.updateGraphicsData(Unknown Source) 
at java.awt.Container.updateGraphicsData(Unknown Source) 
at java.awt.Container.updateGraphicsData(Unknown Source) 
at java.awt.Container.updateGraphicsData(Unknown Source) 
at java.awt.Component.setGraphicsConfiguration(Unknown Source) 
at java.awt.Window.setGraphicsConfiguration(Unknown Source) 
at java.awt.Window.initGC(Unknown Source) 
at java.awt.Window.initDeserializedWindow(Unknown Source) 
at java.awt.Window.readObject(Unknown Source) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
at java.lang.reflect.Method.invoke(Unknown Source) 
at java.io.ObjectStreamClass.invokeReadObject(Unknown Source) 
at java.io.ObjectInputStream.readSerialData(Unknown Source) 
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) 
at java.io.ObjectInputStream.readObject0(Unknown Source) 
at java.io.ObjectInputStream.readObject(Unknown Source) 
at java.awt.Component.readObject(Unknown Source) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) 
at java.lang.reflect.Method.invoke(Unknown Source) 
at java.io.ObjectStreamClass.invokeReadObject(Unknown Source) 
at java.io.ObjectInputStream.readSerialData(Unknown Source) 
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source) 
at java.io.ObjectInputStream.readObject0(Unknown Source) 
at java.io.ObjectInputStream.readArray(Unknown Source) 
at java.io.ObjectInputStream.readObject0(Unknown Source) 
at java.io.ObjectInputStream.readArray(Unknown Source) 
at java.io.ObjectInputStream.readObject0(Unknown Source) 
at java.io.ObjectInputStream.readObject(Unknown Source) 
at EnhancedMinesweeper.actionPerformed(EnhancedMinesweeper.java:316) 
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) 
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) 
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) 
at javax.swing.DefaultButtonModel.setPressed(Unknown Source) 
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source) 
at java.awt.Component.processMouseEvent(Unknown Source) 
at javax.swing.JComponent.processMouseEvent(Unknown Source) 
at java.awt.Component.processEvent(Unknown Source) 
at java.awt.Container.processEvent(Unknown Source) 
at java.awt.Component.dispatchEventImpl(Unknown Source) 
at java.awt.Container.dispatchEventImpl(Unknown Source) 
at java.awt.Component.dispatchEvent(Unknown Source) 
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source) 
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source) 
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source) 
at java.awt.Container.dispatchEventImpl(Unknown Source) 
at java.awt.Window.dispatchEventImpl(Unknown Source) 
at java.awt.Component.dispatchEvent(Unknown Source) 
at java.awt.EventQueue.dispatchEventImpl(Unknown Source) 
at java.awt.EventQueue.access$200(Unknown Source) 
at java.awt.EventQueue$3.run(Unknown Source) 
at java.awt.EventQueue$3.run(Unknown Source) 
at java.security.AccessController.doPrivileged(Native Method) 
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) 
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) 
at java.awt.EventQueue$4.run(Unknown Source) 
at java.awt.EventQueue$4.run(Unknown Source) 
at java.security.AccessController.doPrivileged(Native Method) 
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source) 
at java.awt.EventQueue.dispatchEvent(Unknown Source) 
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) 
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) 
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) 
at java.awt.EventDispatchThread.pumpEvents(Unknown Source) 
at java.awt.EventDispatchThread.pumpEvents(Unknown Source) 
at java.awt.EventDispatchThread.run(Unknown Source) 

at EnhancedMinesweeper.actionPerformed (EnhancedMinesweeper.java:316) - это строка: playField = (EnhancedMinesweeperTile [] []) is.readObject();

Я знаю, что мой массив не равен нулю. Я инициализируюсь его в качестве элемента данных, как это:

private static EnhancedMinesweeperTile[][] playingField = new EnhancedMinesweeperTile[10][10]; // initialize a 2D array of Tiles 

И затем позже я инициализировать каждый и каждый элемент, как это:

 for (int i = 0; i < 10; i++){ 
     for (int j = 0; j < 10; j++){ 
      playingField[i][j] = new EnhancedMinesweeperTile(i, j); 
     } 
    } 

Что не так с этим? Почему я могу сохранить его в файл, но тогда я не могу загрузить его из файла? Это сводит меня с ума.

+1

Почему вы отключили сообщение об ошибке? –

+0

Либо есть еще одно исключение перед «NullPointerException», которое приводит к 'is', все еще являющемуся« null ». Если моя ставка неверна, проверьте методы Serialization в EnhancedMinesweeperTile. Более подробную информацию можно узнать только в том случае, если вы добавили недостающие строки из трассировки стека. –

+0

Инициализатор массива не имеет значения после назначения, поэтому он все равно может быть пустым - если 'is.readObject()' возвращает значение null. – ash

ответ

2

Мне кажется, что EnhancedMinesweeperTile распространяется или передается потомок java.awt.Component. Я бы назвал реализацию Serialization в AWT и Swing «сложной», и именно там происходит исключение. Моя рекомендация: Не сериализуйте классы пользовательского интерфейса. Не видя кода EnhancedMinesweeperTile, невозможно сказать, почему есть NullPointerException.

Я вижу, что причина, по которой вы экономите EnhancedMinesweeperTile[][], заключается в том, что вы хотите сохранить и загрузить состояние игры вашего тральщика. Более чистым, менее подверженным ошибкам, более гибким решением является применение шаблона проектирования MVC - Model View Controller. В вашем случае это означает разбить класс EnhancedMinesweeperTile на два класса. Один класс, который заботится о взгляде и управлении плиткой. И один класс, который заботится о модели, состоянии. Тогда во время сериализации/десериализации вы будете заботиться только о модели, а не о пользовательском интерфейсе.

Кроме того, что менее подвержено ошибкам, разделение модели от пользовательского интерфейса обеспечивает развязку, что, в свою очередь, имеет несколько преимуществ.

Во-первых, вы меняете формат загрузки/сохранения, не изменяя ничего о коде интерфейса. Другим является то, что вы можете изменить пользовательский интерфейс, то есть от Swing до SWT или JavaFX, не изменяя ничего о модели и коде ввода/вывода.

Если EnhancedMinesweeperTile уже есть модель, а не пользовательский интерфейс, то вам нужно реализовать writeObject(ObjectOutputStream) в этом классе, чтобы отделить модель от ничего о пользовательском интерфейсе, что он знает, когда вы сериализовать его. Сериализация сериализует объект-граф, и если EnhancedMinesweeperTile что-то знает о пользовательском интерфейсе, прямо или косвенно, он также будет сериализован. Трассировка стека предполагает, что как-то EnhancedMinesweeperTile знает даже о java.awt.Window.

И, наконец, небольшой совет об упрощении кода ввода-вывода и уменьшении вероятности его появления.

void loadFile() { 
    try (final ObjectInputStream is = new ObjectInputStream(new FileInputStream("savestate.dat"))) { 
     playingField = (EnhancedMinesweeperTile[][]) is.readObject(); 
    } catch (ClassNotFoundException | IOException e1) { 
     e1.printStackTrace(); 
    } 
} 

Этот код имеет несколько преимуществ. Не может быть, что is - null. Поскольку это небольшая функция с отдельным именем, которое в вашем случае вы вызывали бы из actionPerformed(ActionEvent), вы увидите более подробную информацию (хорошо названную функцию) в трассировке стека. И поскольку функция хорошо названа, нет необходимости в каких-либо дополнительных комментариях.

+0

Большое вам спасибо! Ты был прав. Я сохранил все данные, которые мне нужны для хранения в отдельном классе под названием EnhancedMinesweeperTileData, и я включил элемент данных типа EnhancedMinesweeperTileData в EnhancedMinesweeperTile. сохраняя только объект Data, я смог загрузить его без использования всего содержимого GUI. Большое вам спасибо, что я очень ценю вашу доброту и вашу удивительно быструю реакцию –

Смежные вопросы