2011-12-16 28 views
7

Đối với một số Dự án mã byte phân tích cú pháp Java Tôi đọc spec JVM và tìm ra rằng các giá trị bit mask của các trường modifier ảo tập tin lớp máy truy cập dạng Java làKhi nào cờ bộ chỉnh sửa truy cập bytecode JVM cờ 0x1000 (hex) "tổng hợp" được đặt?

ACC_PUBLIC = 0x0001 
    ACC_FINAL = 0x0010 
    ACC_SUPER = 0x0020 # old invokespecial instruction semantics (Java 1.0x?) 
    ACC_INTERFACE = 0x0200 
    ACC_ABSTRACT = 0x0400 
    ACC_SYNTHETIC = 0x1000 
    ACC_ANNOTATION = 0x2000 
    ACC_ENUM = 0x4000 

Bằng cách nào đó tôi không có ý tưởng gì 0x1000 là dành cho . Tôi đã nhìn thấy nó một lần trong một lớp bên trong, nhưng đối với tất cả các lớp bên trong tôi đã kiểm tra kể từ đó, lá cờ này chưa bao giờ được thiết lập. Bây giờ bạn có ý nghĩa của lá cờ này và vị trí/khi nó được đặt?

Trả lời

6

Một yếu tố tổng hợp là bất kỳ yếu tố đó hiện diện trong một tập tin lớp biên soạn nhưng không phải trong mã nguồn của nó được biên dịch từ. Bằng cách kiểm tra một phần tử cho nó là tổng hợp, bạn cho phép phân biệt các yếu tố như vậy cho các công cụ xử lý mã phản chiếu. Đây là khóa học đầu tiên liên quan đến các thư viện sử dụng sự phản chiếu nhưng nó cũng phù hợp với các công cụ khác như IDE không cho phép bạn gọi các phương thức tổng hợp hoặc làm việc với các lớp tổng hợp. Cuối cùng, nó cũng quan trọng đối với trình biên dịch Java để xác minh mã trong quá trình biên dịch của nó để không bao giờ trực tiếp sử dụng các phần tử tổng hợp. Các phần tử tổng hợp chỉ được sử dụng để làm cho thời gian chạy Java hạnh phúc mà chỉ đơn giản là xử lý (và xác minh) mã được phân phối, nơi nó xử lý các phần tử tổng hợp giống với bất kỳ phần tử nào khác.

Bạn đã đề cập các lớp bên trong là một ví dụ nơi các yếu tố tổng hợp được chèn bởi trình biên dịch Java, vì vậy chúng ta hãy nhìn vào một lớp học như:

class Foo { 

    private String foo; 

    class Bar { 

    private Bar() { } 

    String bar() { 
     return foo; 
    } 
    } 

    Bar bar() { 
    return new Bar(); 
    } 
} 

này biên dịch hoàn toàn tốt đẹp nhưng không có các yếu tố tổng hợp, nó sẽ là từ chối bởi một JVM không biết gì về các lớp bên trong. Trình biên dịch Java desugares lớp trên để một cái gì đó như sau:

class Foo { 

    private String foo; 

    String access$100() { // synthetic method 
    return foo; 
    } 

    Foo$Bar bar() { 
    return new Foo$Bar(this, (Foo$1)null); 
    } 

    Foo() { } // NON-synthetic, but implicit! 
} 

class Foo$Bar { 

    private final Foo $this; // synthetic field 

    private Foo$Bar(Foo $this) { // synthetic parameter 
    this.$this = $this; 
    } 

    Foo$Bar(Foo $this, Foo$1 unused) { // synthetic constructor 
    this($this); 
    } 

    String bar() { 
    return $this.access$100(); 
    } 
} 

class Foo$1 { /*empty, no constructor */ } // synthetic class 

Như đã nói, JVM không biết về các lớp bên nhưng thực thi truy cập tin của các thành viên, tức là một lớp bên trong sẽ không thể truy cập các thuộc tính riêng của các lớp kèm theo. Do đó, trình biên dịch Java cần phải thêm cái gọi là bộ truy xuất đến một lớp truy cập để vạch trần tính chất không nhìn thấy được của nó:

  1. Trường foo là tư nhân và có thể do đó chỉ có thể được truy cập từ bên trong Foo. Phương thức access$100 cho thấy trường này với gói của nó, trong đó lớp bên trong luôn luôn được tìm thấy. Phương thức này là tổng hợp vì nó được trình biên dịch thêm vào.

  2. Nhà xây dựng Bar là riêng tư và do đó chỉ có thể được gọi từ bên trong lớp của chính nó. Để khởi tạo một thể hiện của Bar, một hàm tạo (tổng hợp) khác cần trưng ra việc xây dựng một cá thể. Tuy nhiên, các nhà xây dựng có một tên cố định (nội bộ, tất cả chúng được gọi là <init>), do đó chúng tôi không thể áp dụng kỹ thuật cho các trình truy cập phương thức mà chúng tôi chỉ đặt tên cho chúng là access$xxx. Thay vào đó, chúng tôi tạo các trình tạo hàm tạo duy nhất bằng cách tạo kiểu tổng hợp Foo$1.

  3. Để truy cập thể hiện bên ngoài của nó, lớp bên trong cần lưu trữ tham chiếu đến trường hợp này được lưu trữ trong trường tổng hợp $this. Tham chiếu này cần phải được trao cho cá thể bên trong bằng một tham số tổng hợp trong hàm tạo.

ví dụ khác cho các yếu tố tổng hợp các lớp học mà đại diện cho biểu thức lambda, phương pháp cầu khi trọng phương pháp với một kiểu khác nhau chữ ký, việc tạo ra các Proxy lớp hoặc các lớp học được tạo ra bởi các công cụ khác như Maven xây dựng hoặc mã runtime máy phát điện như Byte Buddy (phích cắm không biết xấu hổ).

3

Đó là cờ "tổng hợp", được đặt khi trường hoặc phương thức được tạo bởi trình biên dịch. AFAIK nó dành cho các lớp bên trong, trong đó mắt lưới với quan sát của bạn, và phải được thiết lập khi một tạo phẩm không xuất hiện trong mã nguồn.

http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#88571

+0

Cảm ơn gợi ý. Tôi đã cập nhật câu hỏi cho phù hợp. –

+0

@PeterKofler Đã cập nhật. –

+0

nói "Thành viên lớp không xuất hiện trong mã nguồn phải được đánh dấu bằng thuộc tính Tổng hợp". Điều đó có nghĩa là một thành viên tổng hợp cũng được đánh dấu bằng công cụ sửa đổi truy cập '0x1000' (trong' u2 access_flags')? Nó không rõ ràng. –

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