Java'nın Boolean sınıfı - neden bir numaralandırma olmasın?


11

Bana göre Boolean sınıfı bir enum olarak uygulanacak ideal bir aday.

Kaynak koduna bakıldığında, sınıfın çoğu değişmeden bir numaralandırmaya taşınabilen statik yöntemlerdir, geri kalanı bir numaralandırma olarak çok daha basit hale gelir. Orijinali karşılaştırın (yorumlar ve statik yöntemler kaldırıldı):

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);
   }
}

enum versiyonu ile:

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";
   }
}

Boolean'ın enum haline gelmemesinin bir nedeni var mı?

Equals () yöntemini geçersiz kılmak için bu Sun kodu ise, değerlerini karşılaştırmadan önce iki nesnenin referanslarını karşılaştırmanın çok temel bir denetimi yoktur. Bu eşit () yöntemi olması gerektiğini düşünüyorum:

   public boolean equals(Object obj) {

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

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

4
Bir boole için doğru veya yanlış olmayan başka bir değer öngörüyor musunuz?

1
@MichaelT Bir enum'un 2'den fazla değere sahip olması gerekmez. Java'da anlamsız olurdu çünkü booleans ( if) işlemek için özel bir ifadeye sahiptir, ancak kavramsal / tip teorisi açısından booleans ve enumlar her iki toplamın örneğidir, bu yüzden neden yapmadıklarını sormanın adil olduğunu düşünüyorum aralarındaki boşluğu doldurmaz.
Doval

1
Not: Ayrıca görünür uygulanmasına kaçırmış etmek valueOf(String)arkasında (ENUM en valueOf ters düşecek) ve büyü getBooleanhangi böylece yapabilirsiniz Boolean.valueOf("yes")çok yanlış daha doğrudur döner. Her ikisi de 1.0 spesifikasyonunun bir parçası ve uygun geriye dönük uyumluluk gerektiriyordu.

8
@MichaelT FileNotFabrik olarak!
Donal Fellows

Yanıtlar:


13

Sanırım Java numaralandırmalarının JDK 1.5'e kadar Java programlama diline eklenmediğini söyleyerek başlayabilirim . dolayısıyla Boole sınıfının tanımlandığı ilk günlerde bu çözüm bile bir alternatif değildi.

Bununla birlikte, Java, sürümler arasında geriye dönük uyumluluk sağlama itibarına sahiptir ve bu nedenle, bugün, çözümünüzü iyi bir alternatif olarak görsek bile, eski Boolean'ı kullanarak binlerce kod satırını kırmadan yapamayız. sınıf.


3
Sen bulabilir Java 1.0 java.lang.Boolean yardımcı olmak için dil spec. new Boolean("True")Ve new Boolean("true")ayrıca varsayımsal enum uygulaması ile bazı sorunlara neden olabilir.

Birden çok (değiştirilemez) nesneye izin vermek yanlış görünüyor ve bu nedenle sağlanan Boolean üzerinde Yapıcıları kullanmak iyi bir fikir değil - API belgelerinin dediği gibi.
Yaylası Mark

Dil özelliği, Sınıfların uygulamalarını belirtmediği için bu tür bir soruya yardımcı olmaz. Spesifikasyonu uygulamak en iyi yöntemdir.
Yaylası Mark

13

İşe yaramayan bazı şeyler vardır ve bunları Java'nın booleanının önceki işlevleriyle karşılaştırdığınızda oldukça şaşırtıcı şekilde çalışmazlar.

1.5 ile eklenen bir şey olduğu için boksu görmezden geleceğiz. Varsayımsal olarak, Sun isteseydi, üzerinde yapılan enum Booleanboks gibi davranabilirlerdi class Boolean.

Yine de, daha önceki sınıfın işlevselliğine kıyasla aniden kırılması için başka (kodlayıcıya) başka yollar da var.

ValueOf (String) sorunu

Bunun basit bir örneği:

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"; }
    }
}

Bu kodun çalışması:

doğru
doğru
yanlış
yanlış
"Main" iş parçacığında özel durum java.lang.IllegalArgumentException: BooleanStuff.MyBoolean.FaLsE enum sabiti yok
    java.lang.Enum.valueOf (Enum.java:236)
    BooleanStuff $ MyBoolean.valueOf'da (BooleanStuff.java:17)
    BooleanStuff.main adresinde (BooleanStuff.java:13)

Buradaki sorun ben değil hiçbir şey geçemez olmasıdır TRUEya FALSEkadar valueOf(String).

Tamam ... sadece kendi yöntemimizle geçersiz kılacağız ...

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

Ama ... burada bir sorun var. Sen statik yöntemini geçersiz kılamaz .

Ve böylece, her yerinde geçiyor kodu trueveya Trueveya dışarı hata olacaktır karışık başka vaka - ve oldukça olağanüstü bir çalışma zamanı hariç.

ValueOf ile biraz daha eğlenceli

Çok iyi çalışmayan başka bitler var:

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);
}

Çünkü foo, zaten kutulu bir değeri boks hakkında bir uyarı alıyorum. Ancak, bar kodu bir sözdizimi hatasıdır:

Hata: (7, 24) java: valueOf (BooleanStuff.MyBoolean) için uygun bir yöntem bulunamadı
    yöntemi BooleanStuff.MyBoolean.valueOf (java.lang.String) uygulanamaz
      (BooleanStuff.MyBoolean gerçek bağımsız değişkeni, yöntem çağırma dönüşümü ile java.lang.String öğesine dönüştürülemez)
    java.lang.Enum.valueOf yöntemi (java.lang.Class, java.lang.String) uygulanamaz
      (gerçek ve resmi bağımsız değişken listelerinin uzunluğu farklı olduğu için bağımsız değişkenlerden örnek oluşturulamaz)

Bu sözdizimi hatasını bir Stringtüre dönüştürürsek :

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);
}

Çalışma zamanı hatamızı geri alıyoruz:

doğru
"Main" iş parçacığında kural dışı durum java.lang.IllegalArgumentException: BooleanStuff.MyBoolean.false enum sabiti yok
    java.lang.Enum.valueOf (Enum.java:236)
    BooleanStuff $ MyBoolean.valueOf'da (BooleanStuff.java:11)
    BooleanStuff.main adresinde (BooleanStuff.java:7)

Neden kimse bunu yazsın ki? Bilmiyorum ... ama eskiden işe yarayan ve artık çalışmayan kodu.


Beni yanlış anlamayın, belirli bir değişmez nesnenin sadece bir kopyası fikrini seviyorum. Enum bu sorunu çözer. Şahsen ben böyle bir şey baktı satıcı kodu hata vardı satıcı kodu karşılaştım:

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

O asla çalıştı (yanlış durum başka bir yerde sabit ve bu sabitleme Gerçekten hata ayıklamak için zaman yoktu garip şekillerde olduğu kırdı çünkü Hayır, sorunu çözmedi) . Bu bir numaralandırma olsaydı, bunun yerine bu kod işe yarardı.

Bununla birlikte, enum etrafındaki sözdiziminin gereklilikleri (büyük / küçük harfe duyarlı - arkasındaki enumConstantDirectory'ye gidinvalueOf , diğer numaralandırmalar için bu şekilde çalışması gereken çalışma zamanı hataları) ve statik yöntemlerin çalışma şekli, Boole yerine bir damla olmak.


1
Biri, Java'nın nasıl çalıştığı (ve çalışmadığı) bilgisiyle sıfırdan yeni bir dil çiziyorsa, Boolean nesne türünün sıralamaya benzer bir yapıya sahip olması ... Java'nın şu anda nasıl çalıştığına tam olarak uymuyor. Eminim bunun için kendilerini tekmeleyen bazı dil tasarımcıları vardır. Biri Java 8 ve arayüzlerdeki varsayılan yöntemler gibi şeylerle başlayabilirse, Java'nın birçok yanlış yapısının biraz daha temiz olabileceğinden emin olabilirim - aynı zamanda gerçekten alabilmeyi takdir ediyorum bir Java 1.3 kodu ve hala 1.8 'de derlemek - ve şu anda nerede olduğumuzu.

Bir ofveya fromyöntem ve uygun javadoc eklemek çok zor olmazdı .
assylias

@assylias diğer java kodlarının çoğu valueOfile kongre ve Boolean.valueOf () 1.0 beri var . Ya Enum'lar valueOf'u statik bir yöntem olarak kullanamazlar ya da Boolean kullandığı yöntemden farklı bir yönteme ihtiyaç duyar. Hiçbir kuralı ya da uyumluluğu bozmaz - ve Boolean'ı numaralandırma olmaz. Bundan seçim oldukça basittir.

"Ama ... burada bir sorun var. Statik bir yöntemi geçersiz kılamazsınız." Hiçbir şeyi "geçersiz kılmıyorsunuz" - yöntem yine de bir üst sınıfta mevcut değil. Bunun yerine sorun, yöntemin tüm numaralandırmalar için otomatik olarak tanımlanması ve yeniden tanımlanamamasıdır.
user102008

"Foo için, zaten zaten kutulu bir değeri boks hakkında bir uyarı alıyorum. Ancak, bar için bir sözdizimi hatası:" Bu yanlış bir karşılaştırma. Gelen Boolean.valueOf(Boolean.valueOf("TRUE"))vardır iki farklı valueOf yöntem: valueOf(String)ve valueOf(boolean). Uygulamak unuttuğunuz için sözdizimi hatasıdır valueOf(boolean)in MyBoolean. Ardından için dilinde kodlanmış İki arama arasında autounboxing, orada Booleanama MyBooleansen hayata .Eğer valueOf(boolean) MyBoolean.valueOf(MyBoolean.valueOf("FALSE").booleanValue())eserleri
user102008

2

Büyük olasılıkla, ilkel booleantür bir değildir Enumve ilkel türlerin kutulu sürümleri, kutusuz sürümleriyle neredeyse aynı şekilde davranır. Örneğin

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

(Performans aynı olmayabilir, ancak bu farklı bir konudur.)

Yazabilirsen biraz garip olurdu:

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

Ama değil:

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

1
Bir enum ile çalışmayan if ifadesini de göstermek isteyebilirsiniz.

@MichaelT Derleyicinin hala kutusundan çıkarabileceğini ve ifişi şu anda yaptığı gibi yapabileceğini hayal ediyorum . Öte yandan kadar ekstra işlevler ekledik gerçeğini göz ardı etmek yolu yoktur Booleano booleanyok.
Doval

Whoa ... Java'da booleans için anahtar ifadeleri yazamazsınız? Çılgınca.
Thomas Eding

Boks sınıfları, sadece kutudan çıkarma nedeniyle ilkel olarak hareket eder. Tamsayı'nın + operatörü yok.
Yayla Mark

@HighlandMark Bu doğru, ama benim açımdan kutulu tiplerin ilkel muadilleriyle aynı şekilde kullanılabilir olduklarından emin olmak için büyük acılar yaşadılar. Kutudan çıkarma, uygulamak zorunda oldukları bir şeydir, ücretsiz gelmez.
Doval

0

valueOfSoruna ek olarak (Java düzeyinde bir sorun, JVM düzeyinde iyi çalışabilir), çünkü Booleanbir kamu kurucusu var. Bu kötü bir fikirdi, şu anda kullanımdan kaldırıldı, ama burada kalmak bir fikir.


0

Bunun nedeni, "bool" un "enum" dan çok daha önce Java dilinin bir parçası olmasıydı. Uzun yıllar boyunca "bool" olması çok arzu edilirken, "enum" mevcut değildi. Ancak şimdi "enum başlangıçtan itibaren mevcut olsaydı, bool'u ayrı bir tür yerine enum olarak uygulayabilirdik" diyebilirsiniz.

Enum olarak "bool" ifadesini ifade edebilen Swift'te, "ExpressibleByBooleanLiteral" protokolünü uygulayan "Bool", "DarwinBoolean" ve "ObjCBool" adında üç yapı vardır. (DarwinBoolean bir C veya C ++ boole ile uyumludur, ObjCBool ​​bir Objective-C BOOL ile uyumludur). "true" ve "false" derleyici tarafından tanınan özel değerlerdir ve yalnızca "ExpressibleByBooleanLiteral" protokolünü destekleyen nesneleri başlatmak için kullanılabilir. Bool, bir bit tamsayı içeren dahili bir "_value" değişkenine sahiptir.

Dolayısıyla Bool Swift dilinin bir parçası değil, standart kütüphanenin bir parçasıdır. true ve false dilin bir parçasıdır ve ExpressibleByBooleanLiteral protokolü de öyle.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.