У меня есть очень специфическая техника, которую я использую для такого рода вещей. Это своего рода гибридный подход, который, как я считаю, приводит к самому высокопроизводительному базовому коду io, но при этом поддерживает читабельность и совместимость с простой сериализацией Java.
Отражение, используемое в сериализации Java, исторически считалось медленным и медленным. Но после добавления sun.misc.Unsafe
эта часть на самом деле невероятно быстра. Первоначальное обращение к первому вызову clazz.getDeclaredFields () и других методов типа «getDeclared» из java.lang.Class все еще сохраняется, но они кэшируются на уровне виртуальной машины, поэтому после первого стоят очень дешево (очень заметно) удар.
Оставшиеся издержки Java-сериализации - это запись данных дескриптора класса; имя класса, какие у него поля и какие они типы и т. д. Если бы java-объекты были xml, это было бы как сначала написать xsd, чтобы структура была известна, а затем записать данные xml без тегов. В некоторых ситуациях это действительно довольно эффективно, например, если вам нужно записать более 100 экземпляров одного и того же типа класса в один поток - вы никогда не почувствуете попадание данных дескриптора класса, записываемых один раз во время начало потока.
Но если вам просто нужно написать один экземпляр указанного класса и, может быть, немного больше, есть способ инвертировать вещи в ваших интересах. Вместо передачи объекта в поток, в результате чего сначала пишется дескриптор класса, за которым следуют фактические данные, передавайте поток объекту и переходите прямо к части записи данных. В итоге вы берете на себя ответственность за структурную часть в вашем коде, а не заставляете ObjectOutput / ObjectInput делать это.
Обратите внимание, я также переименовал ваш класс с Map
на TileMap
. Как указывает BalusC, это плохое имя класса.
import java.io.*;
public class TileMap implements Externalizable {
private String name;
private int[][] tiles;
public TileMap(String name, int[][] tiles) {
this.name = name;
this.tiles = tiles;
}
// no-arg constructor required for Externalization
public TileMap() {
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(name);
out.writeInt(tiles.length);
for (int x = 0; x < tiles.length; x++) {
out.writeInt(tiles[x].length);
for (int y = 0; y < tiles[x].length; y++) {
out.writeInt(tiles[x][y]);
}
}
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.name = in.readUTF();
this.tiles = new int[in.readInt()][];
for (int x = 0; x < tiles.length; x++) {
tiles[x] = new int[in.readInt()];
for (int y = 0; y < tiles[x].length; y++) {
tiles[x][y] = in.readInt();
}
}
}
}
Запись будет выглядеть так:
public static void write(TileMap tileMap, OutputStream out) throws IOException {
// creating an ObjectOutputStream costs exactly 4 bytes of overhead... nothing really
final ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(out));
// Instead of oos.writeObject(titleMap1) we do this...
tileMap.writeExternal(oos);
oos.close();
}
И чтение будет выглядеть так:
public static TileMap read(InputStream in) throws IOException, ClassNotFoundException {
final ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(in));
// instantiate TileMap yourself
TileMap tileMap = new TileMap();
// again, directly call the readExternal method
tileMap.readExternal(ois);
return tileMap;
}