325

instanceofオブジェクトに switch case を使用することについて質問があります。

例: 私の問題は Java で再現できます。

if(this instanceof A)
    doA();
else if(this instanceof B)
    doB();
else if(this instanceof C)
    doC():

を使用してどのように実装されswitch...caseますか?

4

24 に答える 24

254

これは、サブタイプ ポリモーフィズムが役立つ典型的なシナリオです。以下をせよ

interface I {
  void do();
}

class A implements I { void do() { doA() } ... }
class B implements I { void do() { doB() } ... }
class C implements I { void do() { doC() } ... }

その後、単に呼び出すことができdo()ますthis

AB、およびを自由に変更Cできない場合は、ビジター パターンを適用して同じことを実現できます。

于 2011-04-07T10:09:24.747 に答える
112

インターフェイスに絶対にコーディングできない場合は、列挙型を仲介として使用できます。

public A() {

    CLAZZ z = CLAZZ.valueOf(this.getClass().getSimpleName());
    switch (z) {
    case A:
        doA();
        break;
    case B:
        doB();
        break;
    case C:
        doC();
        break;
    }
}


enum CLAZZ {
    A,B,C;

}
于 2011-04-07T11:38:58.487 に答える
40

誰かがそれを読む場合に備えて:

Javaでの最良の解決策は次のとおりです。

public enum Action { 
    a{
        void doAction(...){
            // some code
        }

    }, 
    b{
        void doAction(...){
            // some code
        }

    }, 
    c{
        void doAction(...){
            // some code
        }

    };

    abstract void doAction (...);
}

このようなパターンの大きな利点は次のとおりです。

  1. 次のようにします(スイッチはまったくありません):

    void someFunction ( Action action ) {
        action.doAction(...);   
    }
    
  2. 「d」という新しいアクションを追加する場合は、doAction(...) メソッドを実装する必要があります

注: このパターンは Joshua の Bloch "Effective Java (2nd Edition)" で説明されています。

于 2011-10-10T10:07:24.453 に答える
27

できません。ステートメントには、コンパイル時の定数であり、整数に評価されるステートメントswitchのみを含めることができますcase(Java 6 まで、Java 7 では文字列)。

あなたが探しているものは、関数型プログラミングで「パターンマッチング」と呼ばれています。

Java での instanceof の回避も参照してください。

于 2011-04-07T10:06:41.127 に答える
20

上位の回答で説明したように、従来の OOP アプローチは、スイッチの代わりにポリモーフィズムを使用することです。このトリックには、十分に文書化されたリファクタリング パターンもあります: Replace Conditional with Polymorphism。このアプローチに到達するときはいつでも、デフォルトの動作を提供するためにNull オブジェクトも実装するのが好きです。

Java 8 以降では、ラムダとジェネリックを使用して、関数型プログラマーがよく知っているパターン マッチングを実現できます。これはコア言語機能ではありませんが、VAVR ライブラリ(以前の Javaslang ライブラリは 1 つの実装を提供します) です。ドキュメントの例:

Match.ofType(Number.class)
    .caze((Integer i) -> i)
    .caze((String s) -> new BigDecimal(s))
    .orElse(() -> -1)
    .apply(1.0d); // result: -1

これは Java の世界で最も自然なパラダイムではないため、注意して使用してください。ジェネリック メソッドを使用すると、一致した値を型キャストする必要がなくなりますが、たとえばScala のケース クラスのように、一致したオブジェクトを分解する標準的な方法がありません。

于 2015-09-09T06:37:34.820 に答える
12

残念ながら、switch-case ステートメントは定数式を想定しているため、すぐに使用することはできません。これを克服するための 1 つの方法は、クラス名で列挙型の値を使用することです。

public enum MyEnum {
   A(A.class.getName()), 
   B(B.class.getName()),
   C(C.class.getName());

private String refClassname;
private static final Map<String, MyEnum> ENUM_MAP;

MyEnum (String refClassname) {
    this.refClassname = refClassname;
}

static {
    Map<String, MyEnum> map = new ConcurrentHashMap<String, MyEnum>();
    for (MyEnum instance : MyEnum.values()) {
        map.put(instance.refClassname, instance);
    }
    ENUM_MAP = Collections.unmodifiableMap(map);
}

public static MyEnum get(String name) {
    return ENUM_MAP.get(name);
 }
}

これにより、次のような switch ステートメントを使用できます

MyEnum type = MyEnum.get(clazz.getName());
switch (type) {
case A:
    ... // it's A class
case B:
    ... // it's B class
case C:
    ... // it's C class
}
于 2019-03-27T15:21:23.067 に答える
10

私はこれが非常に遅いことを知っていますが、将来の読者のために...

ABC ...のクラスの名前のみに基づく上記のアプローチに注意してください。

ABC ... ( Baseのすべてのサブクラスまたは実装者) がfinalであることを保証できない限り、ABC ... のサブクラスは処理されません。

if、elseif、elseif .. アプローチは、多数のサブクラス/インプリメンターの場合は遅くなりますが、より正確です。

于 2014-02-27T10:50:23.993 に答える
6

いいえ、これを行う方法はありません。ただし、この種の問題を処理する方法としてポリモーフィズムを検討することをお勧めします。

于 2011-04-07T10:09:28.960 に答える
5

このような switch ステートメントの使用は、オブジェクト指向の方法ではありません。代わりに、ポリモーフィズムの力を使用する必要があります。簡単に書く

this.do()

以前に基本クラスを設定した後:

abstract class Base {
   abstract void do();
   ...
}

ABおよびの基本クラスですC

class A extends Base {
    void do() { this.doA() }
}

class B extends Base {
    void do() { this.doB() }
}

class C extends Base {
    void do() { this.doC() }
}
于 2011-04-07T10:10:54.887 に答える
4

スイッチは、バイト、ショート、char、int、文字列、および列挙型でのみ機能することはできません(およびプリミティブのオブジェクトバージョン。Javaバージョンにも依存します。文字列switchはJava 7で編集できます)

于 2011-04-07T10:06:01.933 に答える
3

共通インターフェイスを操作できる場合は、列挙型を追加して、各クラスが一意の値を返すようにすることができます。instanceof や訪問者パターンは必要ありません。

私にとっては、オブジェクト自体ではなく、switch ステートメントにロジックを記述する必要がありました。これが私の解決策でした:

ClassA, ClassB, and ClassC implement CommonClass

インターフェース:

public interface CommonClass {
   MyEnum getEnumType();
}

列挙:

public enum MyEnum {
  ClassA(0), ClassB(1), ClassC(2);

  private int value;

  private MyEnum(final int value) {
    this.value = value;
  }

  public int getValue() {
    return value;
  }

実装:

...
  switch(obj.getEnumType())
  {
    case MyEnum.ClassA:
      ClassA classA = (ClassA) obj;
    break;

    case MyEnum.ClassB:
      ClassB classB = (ClassB) obj;
    break;

    case MyEnum.ClassC:
      ClassC classC = (ClassC) obj;
    break;
  }
...

Java 7 を使用している場合は、列挙型に文字列値を入力できます。大文字と小文字の切り替えブロックは引き続き機能します。

于 2013-10-08T15:45:50.630 に答える
2

これはどう ?

switch (this.name) 
{
  case "A":
    doA();
    break;
  case "B":
    doB();
    break;
  case "C":
    doC();
    break;
  default:
    console.log('Undefined instance');
}
于 2012-11-21T10:25:48.277 に答える
1

クラス名でEnumを作成します。

public enum ClassNameEnum {
    A, B, C
}

オブジェクトのクラス名を見つけます。列挙型にswitchケースを記述します。

private void switchByClassType(Object obj) {

        ClassNameEnum className = ClassNameEnum.valueOf(obj.getClass().getSimpleName());

        switch (className) {
            case A:
                doA();
                break;
            case B:
                doB();
                break;
            case C:
                doC();
                break;
        }
    }
}

お役に立てれば。

于 2018-06-27T05:21:30.743 に答える
1

http://www.vavr.io/を使用して Java 8 でそれを実現する機能的な方法を次に示します。

import static io.vavr.API.*;
import static io.vavr.Predicates.instanceOf;
public Throwable liftRootCause(final Throwable throwable) {
        return Match(throwable).of(
                Case($(instanceOf(CompletionException.class)), Throwable::getCause),
                Case($(instanceOf(ExecutionException.class)), Throwable::getCause),
                Case($(), th -> th)
        );
    }
于 2018-07-19T08:30:19.980 に答える