2013-07-12 28 views
15

Có cách nào để tìm hiểu bằng cách phản ánh liệu một constructor là một trình biên dịch tạo ra constructor mặc định hay không? Hay có cách nào khác?Nhà xây dựng có tạo ra hàm tạo mặc định không?

Đáng ngạc nhiên là phương pháp isSynthetic không cung cấp thông tin này để không thể sử dụng. Và không có chú thích Generated.

public class JavaTest { 
    public void run() throws Exception { 
     out.println(JavaTest.class.getConstructors()[0].isSynthetic()); // Prints false 
     out.println(Arrays.asList(JavaTest.class.getConstructors()[0].getAnnotations())); // Prints [] 
    } 
} 

Câu hỏi này hỏi điều tương tự nhưng đối với C#: Detect compiler generated default constructor using reflection in C#

+5

Tôi đoán câu trả lời sẽ giống như câu trả lời của C# :) – PermGenError

+1

Trình tạo mặc định tự động chắc chắn là lỗi thiết kế ngôn ngữ.Trong một thế giới lý tưởng, nó không tồn tại, vậy tại sao bạn thậm chí còn quan tâm :) Tính năng nào phụ thuộc vào việc phát hiện hàm tạo mặc định? – ZhongYu

+0

Trình tạo mặc định tự động rất tuyệt! Đó là để thực hiện phân tích tĩnh. Nếu tôi biết rằng một hàm khởi tạo là mặc định hơn tôi biết, chỉ bằng cách tìm kiếm khai báo trên lớp, rằng nó là rỗng và không, ví dụ, làm rò rỉ con trỏ 'this' này. – Lii

Trả lời

8

Không, trình biên dịch tạo ra chúng:

Tôi tạo ra các tập tin A.java:

public class A{ 
public String t(){return "";} 
} 

thì:

javac A.java 

và chạy javap -c A để xem nội dung:

Compiled from "A.java" 
public class A { 
    public A(); 
    Code: 
     0: aload_0  
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return   

    public java.lang.String t(); 
    Code: 
     0: ldc   #2     // String 
     2: areturn  
} 

nếu tôi thêm các nhà xây dựng:

public A(){} 

kết quả là:

Compiled from "A.java" 
public class A { 
    public A(); 
    Code: 
     0: aload_0  
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return   

    public java.lang.String t(); 
    Code: 
     0: ldc   #2     // String 
     2: areturn  
} 

nó giống hệt nhau. Tôi đang sử dụng Java 7 với OpenJDK 64 bit, nhưng tôi cá rằng nó giống với tất cả các phiên bản.

EDIT: trên thực tế, cùng một bytecode một mình không đảm bảo rằng thông tin không có ở dạng siêu dữ liệu. Sử dụng trình chỉnh sửa hex và this program có thể thấy rằng có hai byte khác nhau và tương ứng với số dòng (được sử dụng để in dấu vết ngăn xếp), vì vậy thông tin không có trong trường hợp này.

+0

Đường nối hợp lý là một hàm khởi tạo mặc định và một hàm tạo rỗng có cùng một mã byte bytecode. Nhưng vẫn có thể có một số dữ liệu meta với thông tin về điều này. – Lii

+0

Ah, kiểm tra các tập tin lớp học trong một trình soạn thảo dữ liệu thô nên giải quyết nó! Cảm ơn. – Lii

5

Không, không có siêu dữ liệu trong bytecode cho phép bạn phân biệt trình biên dịch tạo ra hàm tạo mặc định từ một trình tạo không được tạo.

Trong hầu hết các trường hợp, trình biên dịch tạo ra các hàm tạo và phương thức được đánh dấu bằng cờ ACC_SYNTHETIC hoặc thuộc tính Synthetic trong mã byte được tạo. Tuy nhiên, có một vài trường hợp ngoại lệ đáng chú ý là mỗi 13.1 mục 7 từ Java Language Spec và 4.7.8 từ jvm-spec

Dưới đây là các bit có liên quan từ JLS:

Bất kỳ cấu trúc được giới thiệu bởi một trình biên dịch Java không có một cấu trúc tương ứng trong mã nguồn phải được đánh dấu là tổng hợp, trừ constructor mặc định, phương pháp lớp khởi tạo, và các giá trị và phương pháp valueOf của lớp Enum

theo như tôi biết, javap không hiển thị cờ ACC_SYNTHETIC nhưng bạn có thể đọc nó qua isSynthetic nếu được đặt.

+0

'javap -verbose' không hiển thị cờ, bao gồm' ACC_SYNTHETIC'. –

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