web-dev-qa-db-ja.com

Javaブールクラス-なぜ列挙ではないのですか?

ブールクラスは列挙型として実装するのに理想的な候補だと私には思えます。

ソースコードを見ると、ほとんどのクラスは静的メソッドであり、変更せずに列挙型に移動できますが、残りは列挙型としてはるかに単純になります。オリジナルを比較する(コメントと静的メソッドは削除されました):

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

列挙型バージョン:

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

ブール値が列挙型になれない理由はありますか?

これがequals()メソッドをオーバーライドするSunコードである場合、2つのオブジェクトの参照を比較してから値を比較するという非常に基本的なチェックが欠落しています。これは、equals()メソッドが次のようになるべきだと私が考える方法です。

   public boolean equals(Object obj) {

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

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

まあ、私はJava列挙がJavaプログラミング言語に追加されなかった JDK 1.5まで)。 と主張することから始めることができると思います。そのため、ブールクラスが定義された当初は、このソリューションは代替手段でさえありませんでした。

そうは言っても、Javaはリリース間の下位互換性を維持するという評判があるため、今日、私たちがあなたのソリューションを優れた代替案と見なしても、数千行を壊さずにそれを行うことはできません。古いBooleanクラスをすでに使用しているコードの例。

13
edalorzo

Javaのbooleanの以前の機能と比較すると、機能しないものや、意外な方法で機能しないものがあります。

ボクシングは1.5で追加されたものであるため、ここでは無視します。仮に、Sunが希望する場合、_enum Boolean_を_class Boolean_で実行されるボクシングと同じように動作させることができます。

しかし、以前のクラスの機能と比較して、これが突然壊れる(コーダーにとって)他の驚くべき方法があります。

ValueOf(String)の問題

この簡単な例は次のとおりです。

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

このコードを実行すると、次のようになります。

 true 
 true 
 false 
 false 
スレッド「メイン」の例外Java.lang.IllegalArgumentException:列挙型定数BooleanStuff.MyBoolean.FaLsE 
 at Java.lang.Enum.valueOf(Enum.Java:236)
 at BooleanStuff $ MyBoolean.valueOf(BooleanStuff.Java:17)
 at BooleanStuff.main(BooleanStuff.Java :13)

ここでの問題は、TRUEまたはFALSE以外の何もvalueOf(String)に渡すことができないことです。

それで大丈夫です...独自のメソッドでオーバーライドするだけです...

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

しかし...ここに問題があります。あなた 静的メソッドをオーバーライドすることはできません

そのため、trueTrueを含むすべてのコード、またはその他の大文字と小文字が混在している場合、エラーが発生します。また、ランタイム例外が発生すると、非常に見事です。

ValueOfでさらに楽しい

うまく機能しない他のいくつかのビットがあります:

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

fooの場合、既にボックス化された値をボックス化することに関する警告が表示されます。ただし、barのコードは構文エラーです。

エラー:(7、24)Java:valueOf(BooleanStuff.MyBoolean)
メソッドに適したメソッドが見つかりません[BooleanStuff.MyBoolean.valueOf(Java.lang.String)は適用されません
(実際の引数BooleanStuff.MyBooleanはメソッド呼び出し変換ではJava.lang.Stringに変換できません)
メソッドJava.lang.Enum.valueOf(Java.lang.Class、Java.lang.String)は適用されません
(実際の引数リストと正式な引数リストは長さが異なるため、引数からインスタンス化できません)

その構文エラーをString型に強制すると、次のようになります。

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

ランタイムエラーが返されます。

 true 
スレッド「メイン」での例外Java.lang.IllegalArgumentException:列挙定数なしBooleanStuff.MyBoolean.false 
 Java.lang.Enum.valueOf(Enum.Java:236 )
 at BooleanStuff $ MyBoolean.valueOf(BooleanStuff.Java:11)​​
 at BooleanStuff.main(BooleanStuff.Java:7)

なぜ誰もがそれを書くのですか? Dunno ...しかし、以前は機能し、機能しなくなったそのコード。


誤解しないでください。私は、与えられた不変オブジェクトのコピーを1つだけにするという考えが本当に好きです。 enumはこの問題を解決します。私は、次のようなベンダーコードからのバグが含まれるベンダーコードに個人的に遭遇しました。

_if(boolValue == new Boolean("true")) { ... }
_

それ決しては働いた (いいえ、間違った状態がどこかで修正されたため、修正しませんでした。これを修正すると、奇妙な方法で、デバッグする時間がないことが壊れました。)。これが列挙型の場合、そのコードは代わりに機能します。

ただし、列挙型周辺の構文の必要性(大文字と小文字を区別-valueOfの背後にある enumConstantDirectory の詳細、他の列挙型でそのように機能する必要があるランタイムエラー)と静的な方法メソッドが機能すると、ブール値の代わりにドロップされることを防ぐために多くの障害が発生します。

13
user40980

最も可能性が高いのは、プリミティブbooleanタイプがEnumではなく、ボックス化されたプリミティブタイプのバージョンがボックス化されていないバージョンとほぼ同じように動作するためです。例えば。

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

(パフォーマンスは同じではないかもしれませんが、それは異なる主題です。)

あなたが書くことができたらそれはちょっと奇妙だろう:

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

だがしかし:

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

valueOfの問題(これはJavaレベルの問題であり、JVMレベルでは問題なく動作する可能性があります)に加えて、Booleanにはパブリックコンストラクターがあるためです。これは悪い考えでしたが、現在は非推奨ですが、これは今後も続く予定です。

0
Konrad Borowski

その理由は、「bool」がJava言語の一部であり、「enum」よりもずっと前だったためです。「enum」は利用できませんでしたが、「bool」はずっと望ましいものでしたが、 。「enumが最初から利用可能であった場合、別の型ではなくenumとしてboolを実装できたはずです」としか言えません。

「bool」を列挙型として表現できたSwiftには、「Bool」、「DarwinBoolean」、「ObjCBool​​」という3つの構造体があり、「ExpressibleByBooleanLiteral」プロトコルを実装しています。 (DarwinBooleanはCまたはC++ boolと互換性があり、ObjCBool​​はObjective-C BOOLと互換性があります)。 「true」と「false」はコンパイラーによって認識される特別な値であり、「ExpressibleByBooleanLiteral」プロトコルをサポートするオブジェクトを初期化するためにのみ使用できます。 Boolには、1ビット整数を含む内部変数「_value」があります。

したがって、BoolはSwift言語の一部ではありませんが、標準ライブラリの一部です。trueとfalseは言語の一部であり、ExpressibleByBooleanLiteralプロトコルも一部です。

0
gnasher729