切换instanceof?

我有一个使用instanceof对象的switch case的问题:

例如:我的问题可以在Java中重现:

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

如何使用switch...case来实现呢?

这是子types多态性帮助的典型场景。 请执行下列操作

 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()

如果您不能自由更改ABC ,则可以使用访问者模式来实现相同的function。

如果你绝对不能编码到一个接口,那么你可以使用枚举作为中介:

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

以防万一,如果有人会读它:

java中的最佳解决scheme是:

 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)”

你不能。 switch语句只能包含编译时常量和计算为整数(最多Java 6和Java 7中的string)的case语句。

在函数式编程中你所要找的叫做“模式匹配”。

另请参阅避免Java中的instanceof

正如在顶级答案中所讨论的,传统的OOP方法是使用多态而不是开关。 这个技巧甚至有一个很好的文档重构模式: replace条件与多态性 。 每当我达到这个方法,我喜欢也实现一个空对象来提供默认行为。

从Java 8开始,我们可以使用lambdas和generics来给我们一些function程序员非常熟悉的东西:模式匹配。 这不是一个核心语言function,但是Java库提供了一个实现。 来自javadoc的示例:

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

这不是Java世界中最自然的范例,所以谨慎使用它。 尽pipegenerics方法可以帮助您避免对匹配值进行types转换,但是我们却缺less一个标准的方法来分解匹配的对象,就像Scala的case类一样 。

不,没有办法做到这一点。 然而,你可能想要做的是把多态性作为处理这些问题的一种方法。

只需创build一个Map,其中的类是关键字,并且function(即lambda或类似)是值。

 Map<Class,Runnable> doByClass = new HashMap<>(); doByClass.put(Foo.class, () -> doAClosure(this)); doByClass.put(Bar.class, this::doBMethod); doByClass.put(Baz.class, new MyCRunnable()); 

//当然,重构此只初始化一次

 doByClass.get(getClass()).run(); 

如果您需要检查exception,而不是实现引发exception的FunctionalInterface,而不是使用Runnable。

我知道这是非常晚,但为未来的读者…

小心以上的方法仅基于ABC …类的名称

除非可以保证ABC …( Base的所有子类或实现者)是最终的,否则ABC …的子类将不会被处理。

尽pipeif,elseif,elseif ..方法对于大量的子类/实现者来说比较慢,但它更加准确。

使用像这样的switch语句不是面向对象的方式。 你应该使用多态的力量。 简单写一下

 this.do() 

以前build立了一个基类:

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

这是ABC的基类:

 class A extends Base { void do() { this.doA() } } class B extends Base { void do() { this.doB() } } class C extends Base { void do() { this.doC() } } 

你不能只使用字节,short,char,int,String和枚举types(和原语的对象版本,它也取决于你的java版本,Strings可以在java 7中switch

这个怎么样 ?

 switch (this.name) { case "A": doA(); break; case "B": doB(); break; case "C": doC(); break; default: console.log('Undefined instance'); } 

如果你可以操作通用接口,你可以添加一个枚举,并让每个类都返回一个唯一的值。 您将不需要instanceof或访问者模式。

对我来说,逻辑需要写在switch语句中,而不是对象本身。 这是我的解决scheme:

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

IMPL:

 ... 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,则可以将枚举的string值和切换大小写块依然可用。

如果你需要通过“这个”对象的types“切换”,这个答案是最好的https://stackoverflow.com/a/5579385/2078368

但是,如果您需要将“开关”应用于任何其他variables。 我会build议另一个解决scheme。 定义如下界面:

 public interface ClassTypeInterface { public String getType(); } 

在想要“切换”的每个课程中实现此接口。 例:

 public class A extends Something implements ClassTypeInterface { public final static String TYPE = "A"; @Override public String getType() { return TYPE; } } 

之后,您可以按以下方式使用它:

 switch (var.getType()) { case A.TYPE: { break; } case B.TYPE: { break; } ... } 

你应该关心的唯一事情 – 保持types在实现ClassTypeInterface的所有类中是唯一的。 这不是一个大问题,因为在任何交集的情况下,您将收到“switch-case”语句的编译时错误。

有一种更简单的方法来模拟使用instanceof的开关结构,你可以通过在你的方法中创build一个代码块并用一个标签来命名它。 然后你使用结构来模拟case语句。 如果一个案例是真的,那么你使用中断LABEL_NAME摆脱你的临时切换结构。

  DEFINE_TYPE: { if (a instanceof x){ //do something break DEFINE_TYPE; } if (a instanceof y){ //do something break DEFINE_TYPE; } if (a instanceof z){ // do something break DEFINE_TYPE; } } 

我认为有理由使用switch语句。 如果你正在使用xText生成Code也许。 或另一种EMF生成的类。

 instance.getClass().getName(); 

返回类实现名称的string。 即:org.eclipse.emf.ecore.util.EcoreUtil

 instance.getClass().getSimpleName(); 

返回简单表示法,即:EcoreUtil

我个人喜欢下面的Java 1.8代码:

  mySwitch("YY") .myCase("AA", (o) -> { System.out.println(o+"aa"); }) .myCase("BB", (o) -> { System.out.println(o+"bb"); }) .myCase("YY", (o) -> { System.out.println(o+"yy"); }) .myCase("ZZ", (o) -> { System.out.println(o+"zz"); }); 

会输出:

 YYyy 

示例代码使用string,但可以使用任何对象types,包括Class。 例如.myCase(this.getClass(), (0) -> ...

需要以下代码片段:

 public Case mySwitch(Object reference) { return new Case(reference); } public class Case { private Object reference; public Case(Object reference) { this.reference = reference; } public Case myCase(Object b, OnMatchDo task) { if (reference.equals(b)) { task.task(reference); } return this; } } public interface OnMatchDo { public void task(Object o); }