Bất biến lớp trong java là gì?


93

Tôi đã truy cập chủ đề này, nhưng ngoài Wikipedia, tôi không tìm thấy bất kỳ tài liệu hoặc bài báo hữu ích nào khác.

Ai có thể giải thích cho tôi bằng những từ đơn giản nghĩa của nó hoặc giới thiệu cho tôi một số tài liệu hay và dễ hiểu được không?


2
+1 cho câu hỏi vì trang Wikipedia có một ví dụ thực sự tuyệt vời về điều gì đó mà tôi không biết bạn có thể làm - thậm chí nó còn có các ví dụ. Tuy nhiên, lời giải thích của họ tốt hơn tôi có thể làm cho bạn; nó khá đơn giản.
iandisme


Nếu bạn quan tâm đến các bất biến wrt Java, có thể bạn sẽ quan tâm đến các hợp đồng cho Java .
Mike Samuel

1
Một lời giải thích đơn giản hơn - < stackoverflow.com/questions/112064/what-is-an-invariant?rq=1 >
ip_x

Câu trả lời:


91

Nó không có ý nghĩa đặc biệt khi tham chiếu đến java.

Một bất biến của lớp chỉ đơn giản là một thuộc tính luôn giữ cho tất cả các trường hợp của một lớp, bất kể mã khác làm gì.

Ví dụ,

class X {
  final Y y = new Y();
}

X có lớp bất biến rằng có một thuộc ytính và nó là không bao giờ nullvà nó có một giá trị kiểu Y.

class Counter {
  private int x;

  public int count() { return x++; }
}

không duy trì được hai bất biến quan trọng

  1. Điều đó countkhông bao giờ trả về giá trị âm vì có thể có dòng dưới.
  2. Những lời kêu gọi đó countđang tăng lên một cách nghiêm túc.

Lớp đã sửa đổi bảo toàn hai bất biến đó.

class Counter {
  private int x;

  public synchronized int count() {
    if (x == Integer.MAX_VALUE) { throw new IllegalStateException(); }
    return x++;
  }
}

nhưng không duy trì được bất biến mà lệnh gọi countluôn thành công bình thường (không có vi phạm TCB ) vì countcó thể ném ra một ngoại lệ hoặc nó có thể chặn nếu một luồng bị khóa sở hữu bộ giám sát của bộ đếm.

Mỗi ngôn ngữ có các lớp giúp dễ dàng duy trì một số bất biến của lớp nhưng không phải các lớp khác. Java cũng không ngoại lệ:

  1. Các lớp Java luôn có hoặc không có các thuộc tính và phương thức, vì vậy các giao diện bất biến rất dễ bảo trì.
  2. Các lớp Java có thể bảo vệ các privatetrường của chúng , vì vậy các bất biến dựa vào dữ liệu riêng tư rất dễ bảo trì.
  3. Các lớp Java có thể là lớp cuối cùng, vì vậy các bất biến dựa vào đó không có mã nào vi phạm một bất biến bằng cách tạo ra một lớp con độc hại có thể được duy trì.
  4. Java cho phép nullcác giá trị lẻn vào theo nhiều cách, vì vậy rất khó để duy trì các bất biến "có giá trị thực".
  5. Java có các luồng có nghĩa là các lớp không đồng bộ hóa gặp khó khăn khi duy trì các bất biến dựa vào các hoạt động tuần tự trong một luồng diễn ra cùng nhau.
  6. Java có các ngoại lệ giúp dễ dàng duy trì các bất biến như "trả về một kết quả với thuộc tính p hoặc không trả về kết quả nào" nhưng khó duy trì các bất biến như "luôn trả về một kết quả".

† - Vi phạm ngoại tác hoặc TCB là sự kiện mà nhà thiết kế hệ thống giả định một cách lạc quan là sẽ không xảy ra.

Thông thường, chúng tôi chỉ tin tưởng rằng phần cứng cơ bản hoạt động như được quảng cáo khi nói về các thuộc tính của các ngôn ngữ cấp cao được xây dựng trên chúng và các lập luận của chúng tôi mà các bất biến giữ lại không tính đến khả năng:

  • Một lập trình viên sử dụng các móc gỡ lỗi để thay đổi các biến cục bộ khi chương trình chạy theo những cách mà mã không thể.
  • Đồng nghiệp của bạn không sử dụng phản chiếu với setAccessibleđể sửa đổi privatecác bảng tra cứu.
  • Loki thay đổi vật lý khiến bộ xử lý của bạn so sánh hai số không chính xác.

Đối với một số hệ thống, TCB của chúng tôi có thể chỉ bao gồm các phần của hệ thống, vì vậy chúng tôi có thể không cho rằng

  • Quản trị viên hoặc daemon đặc quyền sẽ không giết quá trình JVM của chúng tôi,

nhưng chúng ta có thể cho rằng

  • Chúng tôi có thể kiểm tra hệ thống tệp giao dịch đáng tin cậy.

Hệ thống càng cấp cao, thì TCB của nó thường càng lớn, nhưng bạn càng có nhiều thứ không đáng tin cậy ra khỏi TCB của mình, thì khả năng bất biến của bạn càng được giữ vững và hệ thống của bạn sẽ càng đáng tin cậy về lâu dài.


1
"Cái đó countkhông bao giờ trả về cùng một giá trị hai lần" có thực sự được coi là một lớp bất biến không?
ruakh

@ruakh, đó là một câu hỏi hay. Tôi không chắc lắm. Những thứ như tính ổn định của Mã băm (đối với mỗi trường hợp i, i.hashCode () không thay đổi) thường được gọi là bất biến lớp yêu cầu lý luận về các giá trị được trả về trước đó, vì vậy có vẻ hợp lý khi nói rằng "đối với mỗi trường hợp i, i.count () not in (kết quả trước đó của i.count ()) "là một lớp bất biến.
Mike Samuel

@ruakh Đó không phải là một định nghĩa thuần túy sao? Nếu tôi mặc định một điều bất biến như vậy, tại sao không? Nó chắc chắn có thể là một đảm bảo thú vị và quan trọng (ví dụ như để tạo ID duy nhất). Cá nhân tôi cũng nghĩ rằng một cái gì đó như "nếu chỉ có mã luồng đơn truy cập lớp này, các thuộc tính sau sẽ giữ" là hữu ích, nhưng tôi không chắc liệu có thể mở rộng định nghĩa theo cách mà nó chỉ phải giữ trong khi nhất định điều kiện là đúng. (Và xem xét phản ánh về cơ bản thì không thể đảm bảo bất kỳ điều gì thú vị bằng cách khác!)
Voo

1
@ruakh - bạn có thể mô hình hóa nó như một lớp bất biến hoặc một phương thức bất biến. Dù bằng cách nào, mô hình hóa nó yêu cầu một lịch sử khái niệm của các lần gọi phương thức trước đó trên một đối tượng cụ thể. Trên thực tế, bạn thậm chí có thể mô hình điều này như một điều kiện hậu trên phương pháp; nghĩa là giá trị kết quả là giá trị chưa được trả về trước đó.
Stephen C

@Voo: Re: "Đó không phải là một định nghĩa thuần túy sao?": Chắc chắn rồi, nhưng vì câu hỏi ở đây là, "'Bất biến lớp' là gì?", Tôi nghĩ định nghĩa này có liên quan 100%. Có vẻ như tốt hơn, trong chừng mực có thể, sử dụng các ví dụ rõ ràng hoặc cách khác để gọi rõ ràng các trường hợp không rõ ràng. (Tôi không chủ động không đồng ý với ví dụ này, bằng cách này, tôi chỉ ngạc nhiên bởi nó, và được hỏi để chắc chắn.)
ruakh

20

Bất biến có nghĩa là một thứ gì đó phải tuân theo các điều kiện của nó cho dù có bất kỳ thay đổi nào hoặc bất kỳ ai sử dụng / biến đổi nó. Có nghĩa là, một thuộc tính của một lớp luôn đáp ứng hoặc thỏa mãn một số điều kiện ngay cả sau khi trải qua các phép biến đổi bằng cách sử dụng các phương thức public. Vì vậy, khách hàng hoặc người dùng của lớp này được đảm bảo về lớp và thuộc tính của nó.

Ví dụ,

  1. điều kiện trên đối số hàm là, nó phải luôn> 0 (lớn hơn 0) hoặc không được rỗng.
  2. Thuộc tính tối thiểu_account_balance của một lớp tài khoản có trạng thái, nó không thể xuống dưới 100. Vì vậy, tất cả các hàm công cộng phải tôn trọng điều kiện này và đảm bảo lớp bất biến.
  3. sự phụ thuộc dựa trên quy tắc giữa các biến, nghĩa là giá trị của một biến này phụ thuộc vào một biến khác, vì vậy nếu một biến thay đổi, sử dụng một số quy tắc cố định, thì biến khác cũng phải thay đổi. Mối quan hệ này giữa 2 biến phải được giữ nguyên. Nếu nó không, thì bất biến bị vi phạm.

11

Chúng là các dữ kiện phải đúng về một lớp thể hiện. Ví dụ: nếu một lớp có thuộc tính X và bất biến có thể là X phải lớn hơn 0. Theo hiểu biết của tôi, không có phương pháp tích hợp nào để duy trì các bất biến, bạn phải đặt thuộc tính riêng tư và đảm bảo rằng getters và setters của bạn thực thi thuộc tính bất biến.

Có sẵn các chú thích có thể kiểm tra các thuộc tính bằng cách sử dụng phản xạ và đánh chặn. http://docs.oracle.com/javaee/7/api/javax/validation/constraints/package-summary.html

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.