@Override
    public void save(Savable object, OutputStream os) throws IOException {
        // reset some vars
        aliasCount = 1;
        idCount = 1;
        classes.clear();
        contentTable.clear();
        locationTable.clear();
        contentKeys.clear();

        // write signature and version
        os.write(ByteUtils.convertToBytes(FormatVersion.SIGNATURE)); // 1. "signature"
        os.write(ByteUtils.convertToBytes(FormatVersion.VERSION));   // 2. "version"

        int id = processBinarySavable(object);

        // write out tag table
        int classTableSize = 0;
        int classNum = classes.keySet().size();
        int aliasSize = ((int) FastMath.log(classNum, 256) + 1); // make all
                                                                  // aliases a
                                                                  // fixed width

        os.write(ByteUtils.convertToBytes(classNum)); // 3. "number of classes"
        for (String key : classes.keySet()) {
            BinaryClassObject bco = classes.get(key);

            // write alias
            byte[] aliasBytes = fixClassAlias(bco.alias,
                    aliasSize);
            os.write(aliasBytes);                     // 4. "class alias"
            classTableSize += aliasSize;

            // jME3 NEW: Write class hierarchy version numbers
            os.write( bco.classHierarchyVersions.length );
            for (int version : bco.classHierarchyVersions){
                os.write(ByteUtils.convertToBytes(version));
            }
            classTableSize += 1 + bco.classHierarchyVersions.length * 4;

            // write classname size & classname
            byte[] classBytes = key.getBytes();
            os.write(ByteUtils.convertToBytes(classBytes.length)); // 5. "full class-name size"
            os.write(classBytes);                                  // 6. "full class name"
            classTableSize += 4 + classBytes.length;

            // for each field, write alias, type, and name
            os.write(ByteUtils.convertToBytes(bco.nameFields.size())); // 7. "number of fields"
            for (String fieldName : bco.nameFields.keySet()) {
                BinaryClassField bcf = bco.nameFields.get(fieldName);
                os.write(bcf.alias);                                   // 8. "field alias"
                os.write(bcf.type);                                    // 9. "field type"

                byte[] fNameBytes = fieldName.getBytes();
                os.write(ByteUtils.convertToBytes(fNameBytes.length)); // 10. "field-name size"
                os.write(fNameBytes);                                  // 11. "field name"
                classTableSize += 2 + 4 + fNameBytes.length;
            }
        }

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        // write out data to a separate stream
        int location = 0;
        // keep track of location for each piece
        HashMap<String, ArrayList<BinaryIdContentPair>> alreadySaved = new HashMap<>(
                contentTable.size());
        for (Savable savable : contentKeys) {
            // look back at previous written data for matches
            String savableName = savable.getClass().getName();
            BinaryIdContentPair pair = contentTable.get(savable);
            ArrayList<BinaryIdContentPair> bucket = alreadySaved
                    .get(savableName + getChunk(pair));
            int prevLoc = findPrevMatch(pair, bucket);
            if (prevLoc != -1) {
                locationTable.put(pair.getId(), prevLoc);
                continue;
            }

            locationTable.put(pair.getId(), location);
            if (bucket == null) {
                bucket = new ArrayList<BinaryIdContentPair>();
                alreadySaved.put(savableName + getChunk(pair), bucket);
            }
            bucket.add(pair);
            byte[] aliasBytes = fixClassAlias(classes.get(savableName).alias, aliasSize);
            out.write(aliasBytes);            // 17. "class alias"
            location += aliasSize;
            BinaryOutputCapsule cap = contentTable.get(savable).getContent();
            out.write(ByteUtils.convertToBytes(cap.bytes.length)); // 18. "capsule length"
            location += 4; // length of bytes
            out.write(cap.bytes);             // 19. "capsule data"
            location += cap.bytes.length;
        }

        // write out location table
        // tag/location
        int numLocations = locationTable.keySet().size();
        os.write(ByteUtils.convertToBytes(numLocations)); // 12. "number of capsules"
        int locationTableSize = 0;
        for (Integer key : locationTable.keySet()) {
            os.write(ByteUtils.convertToBytes(key));                    // 13. "data id"
            os.write(ByteUtils.convertToBytes(locationTable.get(key))); // 14. "data location"
            locationTableSize += 8;
        }

        // write out number of root ids - hardcoded 1 for now
        os.write(ByteUtils.convertToBytes(1));  // 15. "future use"

        // write out root id
        os.write(ByteUtils.convertToBytes(id)); // 16. "root id"

        // append stream to the output stream
        out.writeTo(os);


        out = null;
        os = null;

        if (debug) {
            logger.fine("Stats:");
            logger.log(Level.FINE, "classes: {0}", classNum);
            logger.log(Level.FINE, "class table: {0} bytes", classTableSize);
            logger.log(Level.FINE, "objects: {0}", numLocations);
            logger.log(Level.FINE, "location table: {0} bytes", locationTableSize);
            logger.log(Level.FINE, "data: {0} bytes", location);
        }
    }
Saves the object into memory then loads it from memory.

Used by tests to check if the persistence system is working.

@param <T> The type of savable.
@param assetManager AssetManager to load assets from.
@param object The object to save and then load.
@return A new instance that has been saved and loaded from the
original object.
jme3-core/src/plugins/java/com/jme3/export/binary/BinaryExporter.java