Tại sao không có tính năng Constant trong Java?


140

Tôi đã cố gắng xác định lý do đằng sau các hằng số trong Java Tôi đã học được rằng Java cho phép chúng ta khai báo các hằng số bằng cách sử dụng finaltừ khóa.

Câu hỏi của tôi là tại sao Java không giới thiệu consttính năng Constant ( ). Vì nhiều người nói rằng nó đến từ C ++, nên trong C ++, chúng tôi có consttừ khóa.

Hãy chia sẻ suy nghĩ của bạn.


2
một consttừ khóa, nhưng không có tính năng cơ bản. Sửa tiêu đề và thẻ của bạn cho phù hợp.
Hầu tước Lorne

Câu trả lời:


142

Mỗi lần tôi chuyển từ mã hóa C ++ nặng sang Java, tôi phải mất một chút thời gian để thích nghi với sự thiếu chính xác trong Java. Cách sử dụng này consttrong C ++ khác nhiều so với việc chỉ khai báo các biến không đổi, nếu bạn không biết. Về cơ bản, nó đảm bảo rằng một đối tượng là bất biến khi được truy cập thông qua một loại con trỏ đặc biệt gọi là con trỏ const Khi ở Java, ở những nơi mà tôi thường muốn trả về một con trỏ const, thay vào đó tôi trả về một tham chiếu với loại giao diện chỉ chứa các phương pháp không nên có tác dụng phụ. Thật không may, điều này không được thi hành bởi ngôn ngữ.

Wikipedia cung cấp các thông tin sau về chủ đề này:

Thật thú vị, đặc tả ngôn ngữ Java coi const là một từ khóa dành riêng - nghĩa là một từ khóa không thể được sử dụng làm định danh biến - nhưng không gán ngữ nghĩa cho nó. Người ta cho rằng việc bảo lưu từ khóa đã xảy ra để cho phép mở rộng ngôn ngữ Java để bao gồm các phương thức const kiểu C ++ và con trỏ tới kiểu const. Vé yêu cầu nâng cao trong Quy trình cộng đồng Java để triển khai tính chính xác của const trong Java đã bị đóng vào năm 2005, ngụ ý rằng tính chính xác của const có thể sẽ không bao giờ tìm được đường vào đặc tả Java chính thức.


10
Java finallà tương tự, mặc dù.
rebierpost

62
Không, không. finalví dụ phương thức làm việc hoàn toàn khác với constcác phương thức C ++ .
dom0

7
@reinierpost finalTừ khóa trên các thuộc tính hoặc biến chỉ đảm bảo rằng một thuộc tính hoặc biến chỉ được gán cho một lần . Người ta vẫn có thể thay đổi trạng thái của đối tượng này bằng cách, ví dụ, gọi một số phương thức có tác dụng phụ. finallà một phần tương tự để sắp xếp phân bổ C ++ về mặt tham chiếu đến một đối tượng chứ không phải là một con trỏ, nhưng đó là tất cả. Đây là lý do ngoài những gì dom0 đã nói.
Tim

9
finaltrong Java dường như hoạt động giống như C ++ constđối với các loại giá trị, nhưng giống với C ++ hơn không phải là T&kiểu tham chiếu
Mark K Cowan

1
cuối cùng là một từ khóa tâm thần phân liệt. Mặc dù nó ngăn chặn việc gán lại, nhưng nó cũng được sử dụng để hiển thị các biến cho các lần đóng. Tôi có thể muốn ngăn chặn việc gán lại nhưng không để lộ các biến đó, nhưng không có cách nào để làm điều đó. Theo ý kiến ​​của tôi, đó là một tính năng ngôn ngữ khá kém.
David Bradley

82

Điều đó constcó nghĩa gì
Đầu tiên, nhận ra rằng ngữ nghĩa của từ khóa "const" có nghĩa là những thứ khác nhau đối với những người khác nhau:

  • tham chiếu chỉ đọc - finalngữ nghĩa Java - chính biến tham chiếu không thể được gán lại để trỏ đến một thể hiện khác (vị trí bộ nhớ), nhưng bản thân thể hiện có thể sửa đổi
  • Tham chiếu chỉ đọc được - Con consttrỏ C / ngữ nghĩa tham chiếu - có nghĩa là tham chiếu này không thể được sử dụng để sửa đổi thể hiện (ví dụ: không thể gán cho các biến thể hiện, không thể gọi các phương thức có thể thay đổi) - chỉ ảnh hưởng đến biến tham chiếu cùng thể hiện có thể sửa đổi thể hiện
  • đối tượng không thay đổi - có nghĩa là bản thân thể hiện không thể được sửa đổi - áp dụng cho thể hiện, do đó, mọi tham chiếu không phải là const sẽ không được phép hoặc không thể được sử dụng để sửa đổi thể hiện
  • Một số kết hợp của trên ?
  • những người khác ?

Tại sao hoặc Tại sao không phải làconst
Thứ hai, nếu bạn thực sự muốn tìm hiểu một số đối số "pro" vs "con", hãy xem cuộc thảo luận theo yêu cầu "lỗi" nâng cao (RFE) này. RFE này yêu cầu tính năng "const" chỉ tham khảo có thể đọc được. Được mở vào năm 1999 và sau đó bị đóng / từ chối bởi Sun vào năm 2005, chủ đề "const" đã được tranh luận mạnh mẽ:

http://bugs.sun.com/ormsdatabase/view_orms.do?orms_id=4211070

Mặc dù có rất nhiều tranh luận tốt ở cả hai phía, một số lý do được trích dẫn (nhưng không nhất thiết phải thuyết phục hoặc rõ ràng) chống lại constbao gồm:

  • có thể có ngữ nghĩa khó hiểu có thể bị lạm dụng và / hoặc lạm dụng (xem phần constnghĩa là gì ở trên)
  • có thể nhân đôi khả năng có sẵn (ví dụ: thiết kế một lớp không thay đổi, sử dụng giao diện không thay đổi)
  • có thể là tính năng creep, dẫn đến nhu cầu thay đổi ngữ nghĩa khác, chẳng hạn như hỗ trợ truyền đối tượng theo giá trị

Trước khi bất cứ ai cố gắng tranh luận với tôi về việc đây là lý do tốt hay xấu, hãy lưu ý rằng đây không phải là lý do của tôi . Chúng chỉ đơn giản là "ý chính" của một số lý do tôi lượm lặt được từ việc lướt qua cuộc thảo luận RFE. Tôi không nhất thiết phải đồng ý với chính họ - Tôi chỉ đơn giản là cố gắng trích dẫn lý do tại sao một số người (không phải tôi) có thể cảm thấy một consttừ khóa có thể không phải là một ý tưởng tốt. Cá nhân, tôi thích nhiều ngữ nghĩa "const" hơn để được giới thiệu với ngôn ngữ một cách rõ ràng.


2
+1 chỉ cho phần thứ hai của câu trả lời của bạn. Nhiều từ khóa có ngữ nghĩa không tầm thường. Là volatileđơn giản như vậy để hiểu? Hay là final? Meh.
einpoklum

OTOH, Java được thiết kế để sử dụng càng ít các tính năng không tầm thường đó càng tốt. Và tôi không nói rằng họ đã đạt được mục tiêu đó (hoặc Java đã không trôi đi khỏi mục tiêu đó). Nhưng loại trừ nó vì lý do đó có thể vẫn có công đức. Rằng có những điều phức tạp khác là lý do nhiều hơn để không giới thiệu thêm (hoặc bạn kết thúc với ngôn ngữ D).
Maarten Bodewes

7

const trong C ++ không có nghĩa là một giá trị là một hằng số.

const trong C ++ ngụ ý rằng khách hàng của hợp đồng cam kết không thay đổi giá trị của nó.

Liệu giá trị của constbiểu thức có thay đổi hay không nếu bạn ở trong môi trường hỗ trợ đồng thời dựa trên luồng.

Vì Java được thiết kế từ đầu để hỗ trợ luồng và khóa đồng thời, nên nó không gây nhầm lẫn bằng cách quá tải thuật ngữ để có ngữ nghĩa final.

ví dụ:

#include <iostream>

int main ()
{
    volatile const int x = 42;

    std::cout << x << std::endl;

    *const_cast<int*>(&x) = 7;

    std::cout << x << std::endl;

    return 0;
}

đầu ra 42 rồi 7.

Mặc dù xđược đánh dấu là const, như một bí danh không const được tạo ra, xkhông phải là hằng số. Không phải mọi trình biên dịch đều yêu cầu volatilehành vi này (mặc dù mọi trình biên dịch đều được phép nội tuyến hằng)

Với các hệ thống phức tạp hơn, bạn có được các bí danh const / non-const mà không sử dụng const_cast, do đó, thói quen suy nghĩ đó có nghĩa là một cái gì đó sẽ không thay đổi sẽ ngày càng nguy hiểm hơn. constchỉ có nghĩa là mã của bạn không thể thay đổi nó mà không cần truyền, không phải là giá trị không đổi.


3
const int x = 42; - x là một hằng số

2
@Neil Nếu bạn có một đối tượng hoặc biến bí danh bởi cả hai con trỏ const và non-const, thì giá trị của bí danh const có thể được thay đổi bằng bí danh không const. Do đó constkhông có nghĩa là một giá trị là hằng số. Nó có nghĩa là máy khách của một giá trị bị hạn chế không làm biến đổi nó. Trong ví dụ của bạn không có bí danh, vì vậy tất cả người dùng đều bị ràng buộc như nhau. Đây không phải là trường hợp nói chung. constảnh hưởng đến khách hàng, không phải giá trị - nó nói rằng bạn không thể thay đổi nó, không phải là nó sẽ không thay đổi.
Pete Kirkham

1
Const-đúng là về những gì lập trình viên nên làm, không phải những gì họ có thể làm . Tôi nghĩ rằng tất cả các bạn dường như đã có điểm đó. Chỉ muốn thêm một vài xu có thể khiến người đọc quan tâm: Thiết kế các mẫu giống như immutable interfaceimmutable objectlà một cách khác (có thể đánh bại bằng cách đúc và phản chiếu) để bắt chước const trong Java. "True" const có thể được thực hiện với SealsObject , than ôi nó phá hủy trường hợp sử dụng của đối tượng của chúng ta.
Martin Andersson

6
Một lưu ý rằng kết quả của chương trình của bạn là không xác định. const_cast không có ở đó để thay đổi các biến const, nó ở đó để chuyển các biến const thành các API không chính xác, nhưng cũng không sửa đổi giá trị. Tôi nghĩ rằng thói quen nghĩ rằng một cái gì đó sẽ không thay đổi là một điều tốt bởi vì nếu chúng thay đổi, điều đó có nghĩa là chương trình của bạn chứa các bản hack có thể bị hỏng bất cứ lúc nào tùy thuộc vào trình biên dịch được sử dụng.
Cygon

1
Sửa đổi giá trị sinh ra thành hằng số là hành vi không xác định. Đĩa của bạn có thể đã được định dạng.
Zhe Yang

5

Đây là một câu hỏi cũ, nhưng tôi nghĩ rằng dù sao tôi cũng sẽ đóng góp 2 xu kể từ khi chủ đề này xuất hiện trong cuộc trò chuyện ngày hôm nay.

Điều này không trả lời chính xác tại sao không có const? nhưng làm thế nào để làm cho lớp học của bạn bất biến. (Thật không may, tôi chưa đủ danh tiếng để đăng bình luận cho câu trả lời được chấp nhận)

Cách để đảm bảo tính bất biến trên một đối tượng là thiết kế các lớp của bạn cẩn thận hơn để trở thành bất biến. Điều này đòi hỏi một chút quan tâm hơn một lớp đột biến.

Điều này quay trở lại Mục 15 hiệu quả của Josh Bloch - Giảm thiểu tính tương tác . Nếu bạn chưa đọc cuốn sách này, hãy lấy một bản sao và đọc nó vài lần tôi đảm bảo nó sẽ giúp bạn "chơi trò chơi java" theo nghĩa bóng .

Trong mục 15 Bloch đề xuất rằng bạn nên hạn chế khả năng biến đổi của các lớp để đảm bảo trạng thái của đối tượng.

Để trích dẫn cuốn sách trực tiếp:

Một lớp bất biến chỉ đơn giản là một lớp mà các thể hiện của chúng không thể được sửa đổi. Tất cả thông tin chứa trong mỗi phiên bản được cung cấp khi nó được tạo và được cố định trong suốt vòng đời của đối tượng. Các thư viện nền tảng Java chứa nhiều lớp bất biến, bao gồm String, các lớp nguyên thủy được đóng hộp và BigInte-ger và BigDecimal. Có nhiều lý do tốt cho việc này: Các lớp bất biến dễ thiết kế, thực hiện và sử dụng hơn các lớp có thể thay đổi. Họ ít bị lỗi và an toàn hơn.

Bloch sau đó mô tả cách làm cho các lớp của bạn bất biến, bằng cách làm theo 5 quy tắc đơn giản:

  1. Không cung cấp bất kỳ phương thức nào sửa đổi trạng thái của đối tượng (ví dụ: setters, hay còn gọi là trình biến đổi )
  2. Đảm bảo rằng lớp không thể được mở rộng (điều này có nghĩa là khai báo chính lớp đó final).
  3. Làm tất cả các lĩnh vực final.
  4. Làm tất cả các lĩnh vực private.
  5. Đảm bảo quyền truy cập độc quyền vào bất kỳ thành phần đột biến. (bằng cách tạo các bản sao phòng thủ của các đối tượng)

Để biết thêm chi tiết, tôi khuyên bạn nên chọn một bản sao của cuốn sách.


3
const trong C ++ linh hoạt hơn nhiều so với bất biến toàn thang. Theo một nghĩa nào đó, "const" có thể được coi là "bất biến trong bối cảnh cụ thể này". Ví dụ: Tôi có một lớp không thay đổi, NHƯNG tôi muốn đảm bảo rằng nó không bị sửa đổi thông qua các API công khai nhất định. Tạo một giao diện (và trả lại cho API công khai đó) như được đề xuất bởi Gunslinger47 đạt được điều tương tự trong Java, nhưng cậu bé - nó xấu (và vì thế - nó bị hầu hết các nhà phát triển Java bỏ qua, dẫn đến sự lộn xộn không cần thiết) .. .
No-Bugs Hare

3

Các ngữ nghĩa của C ++ constrất khác với Java final. Nếu các nhà thiết kế đã sử dụng constnó sẽ gây nhầm lẫn không cần thiết.

Thực tế đó constlà một từ dành riêng cho thấy rằng các nhà thiết kế đã có ý tưởng để thực hiện const, nhưng họ đã quyết định chống lại nó; xem lỗi đóng này . Các lý do đã nêu bao gồm việc thêm hỗ trợ cho kiểu C ++ constsẽ gây ra sự cố tương thích.


-1

Có một cách để tạo các biến "const" trong Java, nhưng chỉ cho các lớp cụ thể. Chỉ cần định nghĩa một lớp với các thuộc tính cuối cùng và phân lớp nó. Sau đó sử dụng lớp cơ sở nơi bạn muốn sử dụng "const". Tương tự, nếu bạn cần sử dụng các phương thức "const", hãy thêm chúng vào lớp cơ sở. Trình biên dịch sẽ không cho phép bạn sửa đổi những gì nó nghĩ là các phương thức cuối cùng của lớp cơ sở, nhưng nó sẽ đọc và gọi các phương thức trên lớp con.


Bạn có thể cung cấp một số ví dụ về điều này, xin vui lòng?
NO_NAME

lớp MYString thực hiện GetString {chuỗi cuối cùng riêng tư aaaa; chuỗi công khai getString (); } lớp MutableString thực hiện GetString {chuỗi riêng aaaa2; chuỗi công khai getString (); chuỗi công khai setString ()}
user1122069

-2

Sẽ có hai cách để xác định các hằng số - conststatic final, với cùng một ngữ nghĩa. Hơn nữa static finalmô tả hành vi tốt hơnconst


@Bozho, bạn nói hành vi tốt hơn Const, nó thế nào? bạn có thể chia sẻ bất kỳ ví dụ nào không
gmhk

tốt, biến là static(không thuộc trường hợp cụ thể) và final- không thể thay đổi.
Bozho

-2

Bạn có thể sử dụng tĩnh cuối cùng để tạo một cái gì đó hoạt động tương tự như Const, tôi đã sử dụng cái này trong quá khứ.

protected static final int cOTHER = 0;
protected static final int cRPM = 1;
protected static final int cSPEED = 2;
protected static final int cTPS = 3;
protected int DataItemEnum = 0;

public static final int INVALID_PIN = -1;
public static final int LED_PIN = 0;

Bị hạ thấp để tối ưu hóa dựa trên tin đồn vì tôi nghe một tin đồn rằng đây là một chiến lược không hiệu quả.
afarley

Tôi loại bỏ tin đồn từ câu trả lời. bạn vẫn có thể sử dụng int int cuối cùng để tạo mã kiểu const.
hamish

Ok, tôi đã loại bỏ downvote của tôi. Có thể một số downvote khác là về câu lệnh chuyển đổi (nó có liên quan gì đến phần còn lại của ví dụ của bạn?)
afarley

trong câu lệnh switch tôi đã sử dụng cRPM như thể nó là const. hoàn toàn đúng, xem xét những điều trên. Vì vậy, có tôi đã loại bỏ các chuyển đổi.
hamish
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.