2015-03-22 20 views
8

Câu hỏi này không phải chủ yếu về Chuỗi. Ngoài sự tò mò về học thuật, tôi muốn biết cách sửa đổi final trên một biến có thể thay đổi hành vi của một chương trình. Ví dụ sau đây cho thấy nó là có thể.Làm cách nào để loại bỏ thay đổi từ khóa cuối cùng theo cách chương trình hoạt động?

Những dòng in true

final String x = "x"; 
System.out.println(x + x == "xx"); 

nhưng những dòng in false

String x = "x"; 
System.out.println(x + x == "xx"); 

Ngoài String thực tập, được có bất kỳ những thứ khác có thể gây ra hành vi của một chương trình để thay đổi nếu sửa đổi final bị xóa khỏi khai báo biến? Tôi giả định rằng chương trình biên dịch có hoặc không có trình sửa đổi.

Vui lòng không bỏ phiếu để đóng nó dưới dạng bản sao của Comparing strings with == which are declared final in Java. Tôi hiểu ví dụ của String.

Tôi hỏi nếu có bất kỳ khác lý do xóa một sửa đổi final có thể tạo sự khác biệt. Xin vui lòng ai đó có thể liên kết đến một câu trả lời hoặc trả lời câu hỏi. Cảm ơn.

+5

Related: http://stackoverflow.com/questions/19418427/comparing-strings-with-which-are-declared-final-in-java – Pshemo

+2

Là 'final' là không đủ, nó phải được * biên dịch- thời gian cố định*. Ví dụ: nếu bạn có phương thức 'public static String method (int i) {return i% 2 == 0? "x": "y"; } 'và bạn khai báo' x' của bạn thành 'chuỗi cuối cùng x = phương thức (0);' (hoặc thậm chí có thể 'chuỗi cuối cùng x = phương thức (trình soạn thảo Random(). nextInt (100));') không thể xử lý là biên dịch-thời gian-không đổi nên nó không thể nối vào thời gian biên dịch để cho 'x + x' trở thành' "x" + "x" 'biểu thức được đánh giá thành' "xx" 'nghĩa đen. – Pshemo

+0

Tôi không downvote, câu trả lời đó giải thích cách 'final' làm cho nó biên dịch hằng số thời gian và giải thích cách nó được lưu trữ vào nhóm chuỗi –

Trả lời

5

Trình sửa đổi final chỉ đảm bảo biến là definitely assigned và cấm chuyển nhượng lại và từ biến đó.

Các trường hợp đặc biệt duy nhất có thể được quan sát là expressly stated in the JLS:

Một biến kiểu nguyên thủy hoặc kiểu String, đó là cuối cùng và khởi tạo với một biểu thức hằng thời gian biên dịch (§15.28), được gọi là một Biến cố định.

Biến là biến không đổi hoặc không có ý nghĩa liên quan đến khởi tạo lớp (§12.4.1), khả năng tương thích nhị phân (§13.1, §13.4.9) và phân bổ xác định (§16).

Có một số tiền khá JLS đọc, và để trang trải các điểm chính: By JLS §13.4.9, bạn sẽ không gặp bất kỳ tác động xấu khi loại bỏ modifier final.

Tuy nhiên, by JLS 17.5, nếu bạn dựa vào sự bảo lãnh của một sợi chỉ nhìn thấy các biến chắc chắn được giao một đối tượng mà nó có thể quan sát, sau đó loại bỏ các biến final sẽ gây ra các biến để không còn được hiển thị cho thread khác .


Vì vậy, nếu chúng ta nhìn vào class initialization đầu tiên, có những quy tắc xung quanh lớp khởi tạo nếu lĩnh vực này là tĩnh và không một biến liên tục:

Một lớp học hoặc giao diện kiểu T sẽ được khởi tạo ngay trước lần xuất hiện đầu tiên của bất kỳ một trong những điều sau đây:

  • T là một lớp và một thể hiện của T được tạo.
  • T là một lớp và một phương thức tĩnh được khai báo bởi T được gọi.
  • Trường tĩnh được khai báo bằng T được gán.
  • Trường tĩnh được khai báo bằng T được sử dụng và trường không phải là biến không đổi (§4.12.4).

Trong JLS §13.1, nó được nêu ra rằng việc thay đổi một lĩnh vực để có thể phá vỡ finalbinary compatibility:

Tài liệu tham khảo để các lĩnh vực mà là các biến đổi (§4.12.4) đều được giải quyết tại thời gian biên dịch để giá trị không đổi được biểu thị. Không có tham chiếu đến trường như vậy nên có mặt trong mã trong một tệp nhị phân (ngoại trừ trong lớp hoặc giao diện chứa trường, sẽ có mã để khởi tạo nó). Trường như vậy phải luôn luôn xuất hiện để được khởi tạo (§12.4.2); giá trị ban đầu mặc định cho loại trường như vậy không bao giờ được quan sát. Xem §13.4.9 để thảo luận.

Từ 13.4.9:

Nếu một lĩnh vực mà không được tuyên bố chính thức được thay đổi để được khai báo cuối cùng, sau đó nó có thể phá vỡ khả năng tương thích với những chương trình tồn tại trước đó nỗ lực để gán giá trị mới đến cánh đồng.

Xóa từ khóa cuối cùng hoặc thay đổi giá trị mà một trường là được khởi tạo không phá vỡ tính tương thích với các tệp nhị phân hiện có.

Nếu một lĩnh vực là một biến đổi (§4.12.4), sau đó xóa các từ khóa thức hoặc thay đổi giá trị của nó sẽ không phá vỡ tính tương thích với mã nhị phân từ trước bằng cách làm cho họ đừng chạy, nhưng họ sẽ không xem bất kỳ giá trị mới nào cho việc sử dụng trường trừ khi chúng được biên dịch lại . Điều này đúng ngay cả khi bản thân việc sử dụng không phải là biểu thức hằng số biên dịch thời gian biên dịch (§15.28) .

Kết quả này là tác dụng phụ của quyết định hỗ trợ điều kiện có điều kiện, như được thảo luận vào cuối §14.21.

Vì vậy, từ đó, hãy cẩn thận về việc đột ngột thay đổi trường thành final. Xóa trường là an toàn.

... nhưng điều đó chỉ áp dụng cho thế giới đơn luồng.Từ JLS 17.5:

Trường khai báo cuối cùng được khởi tạo một lần, nhưng không bao giờ thay đổi theo trường hợp bình thường. Ngữ nghĩa chi tiết của các trường cuối cùng là hơi khác so với ngữ nghĩa của các trường thông thường. Cụ thể, các trình biên dịch có rất nhiều quyền tự do di chuyển lần đọc các trường cuối cùng qua các rào cản đồng bộ và các cuộc gọi đến các phương thức tùy ý hoặc không rõ . Tương ứng, các trình biên dịch được phép giữ giá trị của một trường cuối cùng được lưu trong một sổ đăng ký và không tải lại nó từ bộ nhớ trong các tình huống trong đó trường không phải cuối cùng sẽ phải được tải lại.

các trường cuối cùng cũng cho phép các lập trình viên triển khai các đối tượng không an toàn bất biến thread mà không đồng bộ hóa. Một đối tượng bất biến an toàn chủ đề là được xem là bất biến bởi tất cả các chuỗi, ngay cả khi một cuộc đua dữ liệu được sử dụng để chuyển các tham chiếu đến đối tượng bất biến giữa các luồng. Điều này có thể cung cấp đảm bảo an toàn chống lạm dụng một lớp không thể thay đổi được bằng mã không chính xác hoặc . các trường cuối cùng phải được sử dụng chính xác để cung cấp bảo đảm không thay đổi.

Một đối tượng được coi là được khởi tạo hoàn toàn khi công cụ xây dựng kết thúc. Một chuỗi chỉ có thể thấy tham chiếu đến đối tượng sau khi đối tượng đó được khởi tạo hoàn toàn được đảm bảo để xem giá trị được khởi tạo chính xác cho các trường cuối cùng của đối tượng đó.

Vì vậy, nếu chương trình của bạn dựa vào việc đảm bảo trên để nó hoạt động bình thường, thì việc xóa từ khóa final sẽ có hậu quả trong quá trình truyền.

+0

Trừ khi bạn dựa vào khả năng hiển thị đảm bảo cho các trường 'final', trong trường hợp đó, việc loại bỏ từ khóa' final' cũng không an toàn. – biziclop

+0

Bạn có tham chiếu đến những khả năng hiển thị mà bạn đang nói đến không? – Makoto

+0

Chắc chắn: http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5 – biziclop

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