2016-10-30 16 views
6

Tôi đang đọc sách Effective Java có ví dụ sau. Trong bản ví dụ tác giả bên dưới tham chiếu của các đối tượng có mặt trong ObjectOutputStream bởi dòng sauCách tham chiếu công việc trong Java

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

Tại sao điểm tham chiếu này để các đối tượng có mặt ngày trong ObjectOutputStream? những gì được lưu trữ trong một tài liệu tham khảo?

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

Nhìn thoáng qua, có vẻ như họ đang viết các byte thô cho đối tượng rồi đọc nó? Vì vậy, có lẽ một cái gì đó họ đánh giá trước (ví dụ đã viết đối tượng ra, sao chép byte hơn vào mảng bằng tay) – Rogue

+1

Bạn có thể muốn kiểm tra tài liệu tham chiếu trong nhận xét về mã của bạn: [Java Serialization Specification 6.4.2] (https://docs.oracle.com/javase/7/docs/platform/serialization/spec/protocol.html#10152) –

+0

Tangent… Lớp 'Date' được thay thế bởi các lớp java.time như [' java.time.Instant '] (https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html) và [' 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). Xem [Hướng dẫn] (http://docs.oracle.com/javase/tutorial/datetime/iso/period.html). Và [mã nguồn cho 'Thời lượng'] (http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/f7be58eb30bc/src/share/classes/java/time/Duration.java) triển khai' Serializable' . –

Trả lời

2

Hai "ref" được truyền trực tuyến này không có liên quan gì đến các tham chiếu trong java. (BTW: mảng byte có 5 byte và không chỉ 4 byte như bạn đề cập trong một nhận xét). Mười byte này là một số ma thuật bên trong trong đầu ra tuần tự. Các chi tiết chính xác về định dạng luồng này được mô tả trong chap. 6.4 của "Java Object Serialization Specification" (Các giá trị "71 00 7e 00" phát sinh ngay cả trong ví dụ ở dưới cùng).

Tham chiếu trong chương trình java chứa 4 hoặc 8 byte, tùy thuộc vào nền tảng (32 so với 64 bit). Nó là một con trỏ vào bộ nhớ (java managed), nơi dữ liệu của cá thể đối tượng bắt đầu. Nhưng may mắn là bạn không bao giờ phải đối phó với giá trị này trong java. Tôi nghĩ bạn thậm chí không thể truy cập nó.

3

Tại sao điểm tham chiếu này để các đối tượng có mặt ngày trong ObjectOutputStream?

Khi đối tượng đầu tiên được viết, mỗi đối tượng (và lớp) được cấp một id. Khi bạn thêm các byte thích hợp để người đọc sẽ đọc tài liệu tham khảo # 5 bạn nhận được tham chiếu đối tượng này. Nó chỉ xảy ra rằng hai đối tượng ngày là # 4 và # 5, nhưng nếu bạn đã viết dữ liệu khác nhau, chúng sẽ có một id khác.

những gì được lưu trữ trong tham chiếu?

Trình đọc lưu trữ id và tham chiếu đến đối tượng cho id đó. Một tham chiếu không lưu trữ bất cứ điều gì ngoại trừ đối tượng nó trỏ đến.

+0

Tôi vẫn không hiểu làm sao anh ta đảm bảo rằng 4 byte {0x71, 0, 0x7e, 0, 5} trỏ đến đối tượng Ngày bắt đầu của khoảng thời gian? – raju

+0

@raju là 5 byte giống với điều mà ObjectOutputStream sẽ viết nếu bạn viết lại đối tượng đó. Bằng cách thay đổi giá trị từ # 5 sang # 4, nó lặp lại ngày đầu tiên thay vì ngày đầu tiên. Nếu bạn viết dữ liệu khác một chút thì các id sẽ sai. –

+0

http://stackoverflow.com/questions/5350950/reference-type-size-in-java nói rằng kích thước tham chiếu phụ thuộc vào VM vì vậy không có đảm bảo rằng tham chiếu là 5 byte và nó cũng nói rằng các giá trị byte trong tham chiếu liên quan trực tiếp đến địa chỉ bộ nhớ thực (giá trị tham chiếu * 8 cộng với địa chỉ cơ sở). làm thế nào ông có thể chắc chắn rằng 0x71, 0, 0x7e, 0 sẽ dẫn đến địa chỉ bộ nhớ thực tế của đối tượng ngày tháng. – raju

Các vấn đề liên quan