5

I am reading a book Effective Java which has the following example. In the below example author copies the reference of objects present in the ObjectOutputStream by the following line

byte[] ref = {0x71, 0, 0x7e, 0, 5}; // Ref #5 

Why does this reference point to the date object present in the ObjectOutputStream? what is stored in a reference?

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;

final class Period {
    private final Date start;
    private final Date end;

    /**
     * @param start the beginning of the period
     * @param end the end of the period; must not precede start * @throws IllegalArgumentException
     *        if start is after end
     * @throws NullPointerException if start or end is null
     */
    public Period(Date start, Date end) {
        this.start = new Date(start.getTime());
        this.end = new Date(end.getTime());
        if (this.start.compareTo(this.end) > 0)
            throw new IllegalArgumentException(start + " after " + end);
    }

    public Date start() {
        return new Date(start.getTime());
    }

    public Date end() {
        return new Date(end.getTime());
    }

    public String toString() {
        return start + " - " + end;
    }
    // Remainder omitted
}


public class MutablePeriod {
    // A period instance
    public final Period period;
    // period's start field, to which we shouldn't have access
    public final Date start;
    // period's end field, to which we shouldn't have access
    public final Date end;

    public MutablePeriod() {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream out = new ObjectOutputStream(bos);

            // Serialize a valid Period instance
            out.writeObject(new Period(new Date(), new Date()));
            /*
             * Append rogue "previous object refs" for internal * Date fields in Period. For
             * details, see "Java Object Serialization Specification," Section 6.4.
             */
            byte[] ref = {0x71, 0, 0x7e, 0, 5}; // Ref #5 
            bos.write(ref); // The start field
            ref[4] = 4; // Ref#4
            bos.write(ref); // The end field
            // Deserialize Period and "stolen" Date references
            ObjectInputStream in =
                    new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
            period = (Period) in.readObject();
            start = (Date) in.readObject();
            end = (Date) in.readObject();

        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
raju
  • 4,788
  • 15
  • 64
  • 119
  • 2
    From a glance, looks like they're writing the raw bytes for the object then reading it? So probably something they evaluated beforehand (e.g. wrote the object out, copied bytes over into array by hand) – Rogue Oct 30 '16 at 17:46
  • 1
    You may want to check out the referenced document in the comment of your code: [Java Serialization Specification 6.4.2](https://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html#10152) – Vince Oct 30 '16 at 17:48
  • Tangent… The `Date` class is supplanted by the java.time classes such as [`java.time.Instant`](https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html), and [`Period`](https://docs.oracle.com/javase/8/docs/api/java/time/Period.html) & [`Duration`](https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html). See [Tutorial](http://docs.oracle.com/javase/tutorial/datetime/iso/period.html). And [source code for `Duration`](http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/f7be58eb30bc/src/share/classes/java/time/Duration.java) implementing `Serializable`. – Basil Bourque Oct 30 '16 at 19:14

2 Answers2

3

Why does this reference point to the date object present in the ObjectOutputStream?

When the first object is written, each object (and class) is given an id. When you add the appropriate bytes so that the reader will read the reference #5 you get this object reference. It just happens that the two date objects are #4 and #5, but if you wrote different data they would have a different id.

what is stored in a reference?

The reader stores the id and the reference to the object for that id. A reference doesn't store anything except the object it points to.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • I still dont understand how did he make sure that 4 bytes {0x71, 0, 0x7e, 0, 5} point to the start Date object of period? – raju Oct 30 '16 at 18:03
  • @raju it's 5 bytes which are the same thing it ObjectOutputStream would write if you wrote that object again. By changing the value from #5 to #4 it repeats the first Date instead of the second one. If you write the data a little differently the ids would be wrong. – Peter Lawrey Oct 30 '16 at 18:06
  • http://stackoverflow.com/questions/5350950/reference-type-size-in-java says that reference size depends on the VM so there is no guarantee that reference is 5 bytes and it also states that the byte values in the reference relates directly to actual memory address(reference value *8 plus base address). how can he be sure that 0x71, 0, 0x7e, 0 would lead to the actual memory address of date object. – raju Oct 30 '16 at 18:16
  • 1
    @raju the size of data when it is serialized has little to do with it's size in memory. Also there is very good reasons the representation of data in memory and when serialized is different. The use of `reference index * 8 + base` is only applied for heaps of 28-32 GB, so it is actually rarely used. Obviously trying to store and retrieve memory addresses is a very bad idea as you have no way on knowing what the use of memory or it's layout will be when you deserialize the data. – Peter Lawrey Oct 30 '16 at 18:23
2

These two streamed "ref"s have nothing to do with references in java. (BTW: the byte array has 5 bytes and not only 4 as you mention in a comment). These ten bytes are some internal magic in the serialized output. The exact details about this stream format is described in chap. 6.4 of "Java Object Serialization Specification" (The values "71 00 7e 00" arise even in the example there at the bottom).

A reference in a java program contains either 4 or 8 bytes, depending on the platform (32 vs. 64 bit). It is a pointer into (java managed) memory where the data of the object instance starts. But thankfully you never have to deal with this value in java. I think you cannot even access it.

Heri
  • 4,368
  • 1
  • 31
  • 51