code: public ZooPC readObject(int page, int offs, boolean skipIfCached) {
          long clsOid = in.startReading(page, offs);
          long ts = in.getHeaderTimestamp();
  
          //Read first object:
          long oid = in.readLong();
  
          //check cache
          ZooPC pc = cache.findCoByOID(oid);
          if (skipIfCached && pc != null) {
              if (pc.jdoZooIsDeleted() || !pc.jdoZooIsStateHollow()) {
                  //isDeleted() are filtered out later.
                  return pc;
              }
          }
  
          ZooClassDef clsDef = cache.getSchema(clsOid);
          ObjectReader or = in;
          boolean isEvolved = false;
          if (clsDef.getNextVersion() != null) {
              isEvolved = true;
              GenericObject go = GenericObject.newInstance(clsDef, oid, false, cache);
              readGOPrivate(go, clsDef);
              clsDef = go.ensureLatestVersion();
              in = go.toStream();
              if (oid != in.readLong()) {
                  throw new IllegalStateException();
              }
          }
          
          
          ZooPC pObj = getInstance(clsDef, oid, pc);
          pObj.jdoZooSetTimestamp(ts);
  
          readObjPrivate(pObj, clsDef);
          in = or;
          if (isEvolved) {
              //force object to be stored again
              //TODO is this necessary?
              pObj.jdoZooMarkDirty();
          }
          return pObj;
      }
docs: This method returns an object that is read from the input
  stream.
  @param page page id
  @param offs offset in page
  @param skipIfCached Set 'true' to skip objects that are already in the cache
  @return The read object.