2012-10-01 48 views
11

Bất cứ ai có thể giải thích cách các nguồn Java giống hệt nhau có thể kết thúc biên dịch sang nhị phân các tệp lớp khác nhau không?Các nguồn Java giống hệt nhau được biên dịch thành các lớp nhị phân khác nhau

Câu hỏi đặt ra từ các tình huống sau đây:

Chúng tôi có một ứng dụng khá lớn (800 lớp) mà đã được phân nhánh, tái cơ cấu sau đó reintegrated trở lại vào thân cây. Trước khi tái hòa nhập, chúng tôi sáp nhập thân cây vào chi nhánh, đó là thủ tục tiêu chuẩn.

Kết quả cuối cùng là một tập hợp các thư mục với các nguồn chi nhánh và một tập hợp các thư mục với các nguồn trunk. Sử dụng Beyond Compare, chúng tôi đã có thể xác định rằng cả hai bộ nguồn đều giống hệt nhau. Tuy nhiên, khi biên dịch (cùng một JDK bằng cách sử dụng maven được lưu trữ trong IntelliJ v11), chúng tôi nhận thấy rằng khoảng một tá tệp lớp học khác nhau.

Khi chúng tôi giải mã nguồn cho từng cặp tệp lớp khác nhau, chúng tôi đã kết thúc bằng cùng một nguồn java, do đó, về mặt kết quả cuối cùng, điều đó dường như không quan trọng. Nhưng tại sao nó chỉ là một vài trong số các tập tin khác nhau?

Cảm ơn.


suy nghĩ khác:

Nếu maven/javac biên dịch tập tin trong một chuỗi khác nhau, có thể có ảnh hưởng đến kết quả cuối cùng?

+1

các phiên bản jdk khác nhau? Tôi tưởng tượng các tối ưu hóa có thể khác nhau cho các phiên bản khác nhau. – RNJ

+1

Sử dụng javap -c -v (cảm ơn Peter Lawrey) và xem các kết quả đầu ra tương ứng bằng cách sử dụng Beyond Compare (công cụ tuyệt vời, thích nó!) Tôi có thể xác nhận mục 5 trên câu trả lời của Stephen C (cảm ơn Stephen C) cho một phần câu trả lời ở đây. Trong một số trường hợp, thứ tự hồ bơi không đổi là khác nhau. Tuy nhiên, tôi khá chắc chắn classpath là như nhau cho cả hai, nhưng thứ tự biên dịch có thể khác nhau. – Vicki

Trả lời

5

Giả sử rằng JDK và tùy chọn biên dịch là giống hệt nhau, tôi có thể nghĩ đến 5 nguồn có thể khác biệt:

  1. Timestamps - mỗi tập tin lớp chứa timestamps biên dịch. Trừ khi bạn chạy các bộ sưu tập chính xác cùng một lúc, các bộ sưu tập khác nhau của cùng một tệp sẽ có các dấu thời gian khác nhau.

  2. Đường dẫn tên tệp nguồn - mỗi tệp lớp bao gồm tên đường dẫn của tệp nguồn. Nếu bạn biên dịch hai cây với các tên đường dẫn khác nhau thì các tệp lớp sẽ chứa các tên đường dẫn nguồn khác nhau.

  3. Giá trị của hằng số biên dịch đã nhập - khi một lớp A sử dụng hằng số biên dịch được xác định trong một lớp khác B (xem JLS để định nghĩa "hằng số biên dịch"), giá trị của hằng số được kết hợp vào tệp lớp học A. Vì vậy, nếu bạn biên dịch A so với các phiên bản khác nhau của B (với các giá trị khác nhau cho các hằng số), mã số A có thể khác nhau.

  4. Sự khác biệt về chữ ký của các lớp/phương pháp bên ngoài; ví dụ. nếu bạn thay đổi phiên bản phụ thuộc vào một trong các tệp POM của bạn.

  5. Sự khác biệt trong các đường dẫn lớp xây dựng có thể dẫn đến sự khác biệt về thứ tự các lớp được nhập có thể dẫn đến sự khác biệt không đáng kể theo thứ tự các mục nhập trong Hồ bơi không đổi của tệp lớp. Điều này có thể xảy ra do những thứ như:

    • file xuất hiện trong thứ tự khác nhau trong các thư mục của tập tin JAR bên ngoài,
    • file được biên soạn theo thứ tự khác nhau do các file nguồn là theo thứ tự khác nhau khi công cụ xây dựng của bạn lặp lại chúng hoặc
    • song song trong bản dựng (nếu bạn đã bật tính năng này).

Lưu ý rằng bạn không thường thấy đơn đặt hàng thực tế của tập tin trong thư mục FS, bởi vì các công cụ như lsdir mặc định để sắp xếp các mục trước khi hiển thị chúng.


Tôi nên thêm rằng bước đầu tiên để xác định nguyên nhân của sự khác biệt là tìm ra chính xác chúng là gì. Bạn có thể cần (cần thiết) để làm điều đó một cách khó khăn - bằng cách giải mã thủ công một cặp tệp lớp để xác định các địa điểm mà chúng thực sự khác biệt ... và sự khác biệt thực sự có ý nghĩa gì.

+0

Stephen, tôi có thể thấy không bằng chứng trong việc giải mã các khoản 1,2 và các mục 3 và 4 không áp dụng ở đây (các nguồn, bao gồm cả các POM, giống hệt nhau). Tuy nhiên, tôi nghĩ các mục 5 là khả thi khi trình biên dịch biên dịch có thể khác nhau trong cả hai trường hợp. – Vicki

+0

Cảm ơn Stephen. Tôi nghĩ mục 5 trở đi sẽ trả lời câu hỏi của tôi. – Vicki

1

JDK khác nhau tạo ra các lớp nhị phân khác nhau (tối ưu hóa, nhưng cũng có số phiên bản lớp). Cũng có các tùy chọn biên dịch (một JDK có thể biên dịch theo một định dạng cũ hơn, hoặc nó có thể thêm thông tin gỡ lỗi).

+0

Tôi đã chỉnh sửa để xác nhận cùng một tùy chọn JDK và biên dịch, v.v. – Vicki

1

Các phiên bản Java khác nhau có thể thêm các siêu dữ liệu khác nhau mà thường bị bỏ qua bởi trình giải mã.

Tôi khuyên bạn nên thử sử dụng javap -c -v để biết thêm chi tiết trong tệp. Nếu điều này không giúp bạn có thể sử dụng ASMifierClassVisitor xem xét từng byte.

2

Khi bạn so sánh sử dụng so sánh ngoài, so sánh được thực hiện dựa trên nội dung của tệp. Nhưng trong quá trình xây dựng chỉ dấu thời gian của các tệp nguồn được kiểm tra để thay đổi. Vì vậy, nó thay đổi ngày cuối cùng của tập tin nguồn của bạn thay đổi nó sẽ được biên dịch lại.

+0

Tôi nên làm rõ rằng tất cả các tệp đã được biên dịch cho cả hai bộ nguồn (nghĩa là không có tệp lớp nào tồn tại trước khi biên dịch) – Vicki

1

cùng một JDK cũng có thể có đầu ra khác nhau tùy thuộc vào cách bạn biên dịch. bạn có thể biên dịch có hoặc không có thông tin gỡ lỗi, bạn có thể biên dịch để chạy trong phiên bản cũ hơn, mỗi tùy chọn sẽ dẫn đến các lớp khác.

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