2016-10-30 3 views
6

Я читаю книгу Effective Java, которая имеет следующий пример. В приведенном ниже примере автор копирует ссылочных объектов, присутствующих в ObjectOutputStream следующей строкойКак работает ссылка в Java

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

Почему эта ссылка указывает на дату объекта, присутствующего в ObjectOutputStream? что хранится в ссылке?

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); 
     } 
    } 
} 
+2

С первого взгляда, похоже, они записывают необработанные байты для объекта, а затем читают его? Возможно, что-то они заранее оценили (например, выписали объект, скопировали байты в массив вручную) – Rogue

+1

Возможно, вы захотите проверить ссылочный документ в комментарии к вашему коду: [Java Serialization Specification 6.4.2] (https://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html#10152) –

+0

Tangent ... Класс 'Date' вытесняется классами java.time, такими как [' java.time.Instant '] (https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html) и [' 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). См. [Учебник] (http://docs.oracle.com/javase/tutorial/datetime/iso/period.html). И [исходный код для 'Duration'] (http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/f7be58eb30bc/src/share/classes/java/time/Duration.java), реализующий' Serializable' , –

ответ

2

Эти две потоковые «ссылки» не имеют никакого отношения к ссылкам в java. (BTW: массив байтов имеет 5 байтов и не только 4, как вы отметили в комментарии). Эти десять байтов - это некоторая внутренняя магия в сериализованном выходе. Точные сведения об этом поточном формате описаны в гл. 6.4 «Спецификация сериализации объектов Java» (значения «71 00 7e 00» возникают даже в примере, расположенном внизу).

Ссылка в программе Java содержит 4 или 8 байт, в зависимости от платформы (32 против 64 бит). Это указатель на (управляемую java) памятью, где начинаются данные экземпляра объекта. Но, к счастью, вам никогда не придется разбираться в этой ценности в java. Я думаю, вы даже не можете его получить.

3

Почему эта ссылка указывает на дату объекта, присутствующего в ObjectOutputStream?

Когда первый объект записан, каждому объекту (и классу) присваивается идентификатор. Когда вы добавляете соответствующие байты, чтобы читатель прочитал ссылку # 5, вы получите эту ссылку на объект. Просто бывает, что два объекта даты - это # ​​4 и # 5, но если вы написали разные данные, у них будет другой идентификатор.

Что хранится в ссылке?

Читатель хранит идентификатор и ссылку на объект для этого идентификатора. Ссылка не хранит ничего, кроме объекта, на который указывает.

+0

Я все еще не понимаю, как он удостоверился, что 4 байта {0x71, 0, 0x7e, 0, 5} указывают на объект даты начала периода? – raju

+0

@raju это 5 байт, это то же самое, что и ObjectOutputStream, если вы снова написали этот объект. Изменяя значение от # 5 до # 4, он повторяет первую Дату вместо второй. Если вы напишете данные немного иначе, идентификаторы будут ошибочными. –

+0

http://stackoverflow.com/questions/5350950/reference-type-size-in-java говорит, что размер ссылки зависит от виртуальной машины, поэтому нет гарантии, что ссылка составляет 5 байтов, а также указывает, что значения байтов в ссылка относится непосредственно к фактическому адресу памяти (опорное значение * 8 плюс базовый адрес). как он может быть уверен, что 0x71, 0, 0x7e, 0 приведет к фактическому адресу памяти объекта даты. – raju

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