Lớp Boolean của Java - tại sao không phải là enum?


11

Dường như với tôi rằng lớp Boolean là một ứng cử viên lý tưởng để được thực hiện như một enum.

Nhìn vào mã nguồn, hầu hết các lớp là các phương thức tĩnh có thể được chuyển không đổi sang một enum, phần còn lại trở nên đơn giản hơn nhiều như một enum. So sánh bản gốc (bình luận và phương thức tĩnh được loại bỏ):

public final class Boolean implements java.io.Serializable,
                                      Comparable<Boolean>
{
   public static final Boolean TRUE = new Boolean(true);
  public static final Boolean FALSE = new Boolean(false);
   private final boolean value;
   public Boolean(boolean value) {
       this.value = value;
   }
   public Boolean(String s) {
       this(toBoolean(s));
   }
   public boolean booleanValue() {
       return value;
   }
   public String toString() {
       return value ? "true" : "false";
   }
   public int hashCode() {
       return value ? 1231 : 1237;
   }
   public boolean equals(Object obj) {
       if (obj instanceof Boolean) {
           return value == ((Boolean)obj).booleanValue();
       }
       return false;
   }
   public int compareTo(Boolean b) {
       return compare(this.value, b.value);
   }
}

với phiên bản enum:

public enum Boolean implements Comparable<Boolean>
{
   FALSE(false), TRUE(true);
   private Boolean(boolean value) {
       this.value = value;
   }
   private final boolean value;
   public boolean booleanValue() {
       return value;
   }

   public String toString() {
       return value ? "true" : "false";
   }
}

Có bất kỳ lý do tại sao Boolean không thể trở thành một enum?

Nếu đây là mã Sun để ghi đè phương thức equals (), thì nó thiếu một kiểm tra rất cơ bản để so sánh các tham chiếu của hai đối tượng trước khi so sánh các giá trị của chúng. Đây là cách tôi nghĩ phương thức equals () nên:

   public boolean equals(Object obj) {

       if (this == obj) {
          return true;
       }

       if (obj instanceof Boolean) {
           return value == ((Boolean)obj).booleanValue();
       }
       return false;
   }

4
Bạn có thấy trước một giá trị khác cho một boolean không đúng hay sai không?

1
@MichaelT Một enum không cần phải có nhiều hơn 2 giá trị. Nó sẽ là vô nghĩa trong Java bởi vì nó có một tuyên bố chuyên biệt để xử lý booleans ( if) nhưng từ quan điểm lý thuyết / loại quan điểm của booleans và enums đều là các trường hợp của các kiểu tổng, vì vậy tôi nghĩ thật công bằng khi hỏi tại sao chúng không 't thu hẹp khoảng cách giữa họ.
Doval

1
Lưu ý: Có vẻ như bạn đã bỏ lỡ việc triển khai valueOf(String)(điều này sẽ mâu thuẫn với valueOf của enum) và phép thuật đằng sau getBooleancó thể khiến nó Boolean.valueOf("yes")trả về đúng chứ không phải sai. Cả hai đều là một phần của thông số 1.0 và sẽ cần khả năng tương thích ngược thích hợp.

8
@MichaelT FileNotFound tất nhiên!
Donal Fellows

Câu trả lời:


13

Chà, tôi đoán rằng tôi có thể bắt đầu bằng cách lập luận rằng các liệt kê Java không được thêm vào ngôn ngữ lập trình Java cho đến khi JDK 1.5. và do đó, giải pháp này thậm chí không phải là một giải pháp thay thế trong những ngày đầu khi lớp Boolean được xác định.

Điều đó đang được nói, Java có tiếng là giữ khả năng tương thích ngược giữa các bản phát hành và vì vậy, ngay cả khi chúng ta, ngày nay, có thể coi giải pháp của bạn là một giải pháp thay thế tốt, chúng ta không thể làm điều đó mà không phá vỡ hàng ngàn dòng mã đã sử dụng Boolean cũ lớp học.


3
Bạn có thể tìm thấy đặc tả ngôn ngữ Java 1.0 cho java.lang.Boolean để được trợ giúp. Các new Boolean("True")new Boolean("true")cũng có thể gây ra một số vấn đề với việc thực hiện enum giả.

Có vẻ sai khi cho phép nhiều đối tượng (không thay đổi) và do đó, sử dụng Trình xây dựng được cung cấp trên Boolean không phải là một ý tưởng hay - như tài liệu API nói.
Cao nguyên Mark

Thông số ngôn ngữ sẽ không giúp ích cho loại câu hỏi này vì nó không chỉ định việc triển khai các Lớp học. Đây là cách tốt nhất để thực hiện các đặc điểm kỹ thuật.
Cao nguyên Mark

13

Có một số thứ không hoạt động và không hoạt động theo những cách khá đáng ngạc nhiên khi bạn so sánh chúng với chức năng trước đây của boolean của Java.

Chúng ta sẽ bỏ qua quyền anh vì đó là thứ được thêm vào 1.5. Theo giả thuyết, nếu Sun muốn, họ có thể khiến họ enum Booleancư xử giống như quyền anh được biểu diễn trên class Boolean.

Tuy nhiên, có những cách đáng ngạc nhiên khác (đối với người viết mã) rằng điều này sẽ đột nhiên bị phá vỡ so với chức năng của lớp trước đó.

Vấn đề valueOf (Chuỗi)

Một ví dụ đơn giản về điều này là:

public class BooleanStuff {
    public static void main(String args[]) {
        Boolean foo = Boolean.valueOf("TRUE");
        System.out.println(foo);
        foo = Boolean.valueOf("TrUe");
        System.out.println(foo);
        foo = Boolean.valueOf("yes");  // this is actually false
        System.out.println(foo);

        // Above this line is perfectly acceptable Java 1.3
        // Below this line takes Java 1.5 or later

        MyBoolean bar;
        bar = MyBoolean.valueOf("FALSE");
        System.out.println(bar);
        bar = MyBoolean.valueOf("FaLsE");
        System.out.println(bar);
    }

    enum MyBoolean implements Comparable<MyBoolean> {
        FALSE(false), TRUE(true);
        private MyBoolean(boolean value) { this.value = value; }
        private final boolean value;
        public boolean booleanValue() { return value; }
        public String toString() { return value ? "true" : "false"; }
    }
}

Việc chạy mã này mang lại:

thật
thật
sai
sai
Ngoại lệ trong luồng "chính" java.lang.IllegalArgumentException: Không có hằng số enum BooleanStuff.MyBoolean.FaLsE
    tại java.lang.Enum.valueOf (Enum.java:236)
    tại BooleanStuff $ MyBoolean.valueOf (BooleanStuff.java:17)
    tại BooleanStuff.main (BooleanStuff.java:13)

Vấn đề ở đây là tôi không thể vượt qua bất cứ thứ gì không TRUEhoặc không FALSEthể valueOf(String).

Không sao đâu ... chúng ta sẽ ghi đè lên nó bằng phương pháp riêng của chúng ta ...

    public static MyBoolean valueOf(String arg) {
        return arg.equalsIgnoreCase("true") ? TRUE : FALSE;
    }

Nhưng ... có một vấn đề ở đây. Bạn không thể ghi đè một phương thức tĩnh .

Và do đó, tất cả các mã được truyền xung quanh truehoặc Truemột số trường hợp khác sẽ bị lỗi - và khá ngoạn mục với một ngoại lệ thời gian chạy.

Một số niềm vui khác với valueOf

Có một số bit khác không hoạt động tốt:

public static void main(String args[]) {
    Boolean foo = Boolean.valueOf(Boolean.valueOf("TRUE"));
    System.out.println(foo);

    MyBoolean bar = MyBoolean.valueOf(MyBoolean.valueOf("FALSE"));
    System.out.println(bar);
}

Đối với foo, tôi chỉ nhận được một cảnh báo về quyền anh đã được đóng hộp. Tuy nhiên, mã cho thanh là một lỗi cú pháp:

Lỗi: (7, 24) java: không tìm thấy phương thức phù hợp cho valueOf (BooleanStuff.MyBoolean)
    phương thức BooleanStuff.MyBoolean.valueOf (java.lang.String) không áp dụng
      (đối số thực tế BooleanStuff.MyBoolean không thể được chuyển đổi thành java.lang.String bằng cách chuyển đổi lời gọi phương thức)
    phương thức java.lang.Enum.valueOf (java.lang.Class, java.lang.String) không áp dụng
      (không thể khởi tạo từ các đối số vì danh sách đối số thực tế và chính thức khác nhau về độ dài)

Nếu chúng tôi ép lỗi cú pháp đó trở lại thành một Stringloại:

public static void main(String args[]) {
    Boolean foo = Boolean.valueOf(Boolean.valueOf("TRUE"));
    System.out.println(foo);

    MyBoolean bar = MyBoolean.valueOf(MyBoolean.valueOf("FALSE").toString());
    System.out.println(bar);
}

Chúng tôi nhận được lỗi thời gian chạy của chúng tôi trở lại:

thật
Ngoại lệ trong luồng "chính" java.lang.IllegalArgumentException: Không có hằng số enum BooleanStuff.MyBoolean.false
    tại java.lang.Enum.valueOf (Enum.java:236)
    tại BooleanStuff $ MyBoolean.valueOf (BooleanStuff.java:11)
    tại BooleanStuff.main (BooleanStuff.java:7)

Tại sao bất cứ ai sẽ viết điều đó? Dunno ... nhưng mã của nó đã từng hoạt động và sẽ không còn hoạt động nữa.


Đừng hiểu sai ý tôi, tôi thực sự thích ý tưởng chỉ có một bản sao của một vật thể bất biến nhất định. Enum không giải quyết vấn đề này Cá nhân tôi đã gặp mã nhà cung cấp có lỗi trong mã nhà cung cấp trông giống như thế này:

if(boolValue == new Boolean("true")) { ... }

Điều đó không bao giờ hoạt động (Không, tôi đã không sửa nó vì trạng thái không chính xác đã được sửa ở một nơi khác và việc sửa lỗi này đã phá vỡ điều đó theo những cách kỳ lạ mà tôi thực sự không có thời gian để gỡ lỗi) . Nếu đây là một enum, mã đó sẽ hoạt động thay thế.

Tuy nhiên, sự cần thiết của cú pháp xung quanh enum (phân biệt chữ hoa chữ thường - đào sâu vào enumConstantDirectory phía sau valueOf, các lỗi thời gian chạy cần hoạt động theo cách đó cho các enum khác) và cách các phương thức tĩnh hoạt động khiến một số thứ bị phá vỡ ngăn nó là một sự thay thế cho Boolean.


1
Nếu một người đang thiết kế, từ đầu một ngôn ngữ mới với kiến ​​thức về cách Java hoạt động (và không), thì loại đối tượng Boolean là một cấu trúc giống như enum ... nó hoàn toàn không phù hợp với cách Java hoạt động. Tôi chắc rằng có một số nhà thiết kế ngôn ngữ tự đá mình vì nó. Nếu một người có thể bắt đầu lại với Java 8 và những thứ như các phương thức mặc định trong các giao diện, tôi chắc chắn rằng rất nhiều lỗi sai của Java có thể đã được thực hiện khá hơn một chút - đồng thời tôi thực sự đánh giá cao việc có thể thực hiện một số mã Java 1.3 và vẫn biên dịch nó thành 1.8 - và đó là nơi chúng ta đang ở.

Sẽ không quá khó để thêm một ofhoặc một fromphương thức và javadoc thích hợp.
assylias

@assylias quy ước với phần lớn mã java khác là valueOfvà Boolean.valueOf () đã ở đó kể từ 1.0 . Hoặc Enums sẽ không thể sử dụng valueOf như một phương thức tĩnh hoặc Boolean sẽ cần một phương thức khác với phương thức mà nó đã sử dụng. Làm cả hai phá vỡ quy ước hoặc tương thích - và không có Boolean cũng là một enum phá vỡ. Từ điều này, sự lựa chọn khá đơn giản.

"Nhưng ... có một vấn đề ở đây. Bạn không thể ghi đè một phương thức tĩnh." Bạn không "ghi đè" bất cứ điều gì - dù sao phương thức này không tồn tại trong siêu lớp. Vấn đề thay vào đó là phương thức được xác định tự động cho tất cả các enum và bạn không thể xác định lại nó.
dùng102008

"Đối với foo, tôi chỉ nhận được một cảnh báo về quyền anh đã được đóng hộp. Tuy nhiên, mã cho thanh là một lỗi cú pháp:" Đây là một so sánh không chính xác. Trong Boolean.valueOf(Boolean.valueOf("TRUE")), có hai valueOf phương pháp khác nhau : valueOf(String)valueOf(boolean). Lỗi cú pháp là do bạn quên thực hiện valueOf(boolean)trong MyBoolean. Sau đó, có hộp thư tự động giữa hai cuộc gọi, được mã hóa bằng ngôn ngữ Booleannhưng không MyBoolean. Nếu bạn triển khai valueOf(boolean) MyBoolean.valueOf(MyBoolean.valueOf("FALSE").booleanValue())công việc
user102008

2

Rất có thể bởi vì kiểu nguyên thủy booleankhông phải là một Enum, và các phiên bản được đóng hộp của các kiểu nguyên thủy hoạt động gần như giống hệt với phiên bản không có hộp của chúng. Ví dụ

Integer x = 5;
Integer y = 7;
Integer z = x + y;

(Hiệu suất có thể không giống nhau, nhưng đó là một chủ đề khác.)

Sẽ thật kỳ lạ nếu bạn có thể viết:

Boolean b = Boolean.TRUE;
switch (b) {
case Boolean.TRUE:
    // do things
    break;
case Boolean.FALSE:
    // do things
    break;
}

nhưng không:

boolean b = true;
switch(b) {
case true:
    // do things
    break;
case false:
    // do things
    break;
}  

1
Bạn có thể muốn hiển thị câu lệnh if sẽ không hoạt động với enum.

@MichaelT Tôi tưởng tượng trình biên dịch vẫn có thể mở hộp và làm cho ifcông việc giống như hiện tại. Mặt khác, không có cách nào để bỏ qua thực tế là bạn đã thêm chức năng bổ sung cho Booleanđiều booleanđó không có.
Doval

Whoa ... bạn không thể viết câu lệnh chuyển đổi cho booleans trong Java? Thật điên rồ.
Thomas Eding

Các lớp quyền anh chỉ hoạt động như người nguyên thủy do bỏ hộp. Số nguyên không có toán tử +.
Cao nguyên Mark

@HighlandMark Điều đó đúng, nhưng quan điểm của tôi là họ đã trải qua những khó khăn lớn để đảm bảo các loại hình hộp có thể sử dụng theo cách tương tự như các đối tác nguyên thủy của chúng. Unboxing là thứ họ phải thực hiện, nó không miễn phí.
Doval

0

Ngoài valueOfvấn đề (là một vấn đề ở cấp Java, nó có thể hoạt động tốt ở cấp JVM), vì nó Booleancó một hàm tạo công khai. Đó là một ý tưởng tồi, hiện không được chấp nhận, nhưng đó là một ý tưởng ở đây.


0

Lý do là "bool" là một phần của ngôn ngữ Java sớm hơn nhiều so với "enum". Trong nhiều năm, "bool" rất mong muốn có được, trong khi "enum" không có sẵn. Chỉ bây giờ bạn có thể nói "nếu enum đã có sẵn từ đầu, thì chúng ta có thể thực hiện bool như một enum thay vì một loại riêng biệt".

Trong Swift, có thể biểu thị "bool" là enum, có ba cấu trúc có tên "Bool", "DarwinBoolean" và "ObjCBool" thực hiện giao thức "ExpressibleByBooleanLiteral". (DarwinBoolean tương thích với bool C hoặc C ++, ObjCBool ​​tương thích với BOOL Objective-C). "true" và "false" là các giá trị đặc biệt được trình biên dịch nhận ra và chỉ có thể được sử dụng để khởi tạo các đối tượng hỗ trợ giao thức "ExpressibleByBooleanLiteral". Bool có một biến nội bộ "_value" chứa số nguyên một bit.

Vì vậy, Bool không phải là một phần của ngôn ngữ Swift, mà là của thư viện chuẩn. đúng và sai là một phần của ngôn ngữ và giao thức ExpressibleByBooleanLiteral cũng vậy.

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.