我有一个问题,使用开关情况的instanceof对象:

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

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

如何使用switch…case实现它?


当前回答

如果您想避免If (){} else If{}的冗长,您可以考虑将这个文件切换到kotlin,并将类似于开关的when表达式与is操作符结合使用。

在任何情况下,Kotlin和java文件都可以共存于一个项目中,并生成一个可以在JVM中运行的jar。

when (this) { //switch-like statement in kotlin supporting class-pattern-matching and smart casts via `is` operator.
    is A -> doA()
    is B -> doB()
    is C -> doC()
}

其他回答

java 7 +

public <T> T process(Object model) {
    switch (model.getClass().getSimpleName()) {
    case "Trade":
        return processTrade((Trade) model);
    case "InsuranceTransaction":
        return processInsuranceTransaction((InsuranceTransaction) model);
    case "CashTransaction":
        return processCashTransaction((CashTransaction) model);
    case "CardTransaction":
        return processCardTransaction((CardTransaction) model);
    case "TransferTransaction":
        return processTransferTransaction((TransferTransaction) model);
    case "ClientAccount":
        return processAccount((ClientAccount) model);
    ...
    default:
        throw new IllegalArgumentException(model.getClass().getSimpleName());
    }
}

你可以通过在getSimpleName中引入常量并使用完整的类名来省略字符串操作,这甚至更快:

public static final TRADE = Trade.class.getName();
...
switch (model.getClass().getName()) {
case TRADE:

正如前面的回答所讨论的,传统的面向对象方法是使用多态性而不是开关。对于这种技巧,甚至有一个经过良好记录的重构模式:用多态性替换Conditional。每当我使用这种方法时,我也喜欢实现一个Null对象来提供默认行为。

从Java 8开始,我们可以使用lambda和泛型来提供函数式程序员非常熟悉的东西:模式匹配。它不是语言的核心特性,但是VAVR库(以前是Javaslang库)提供了一个实现。文档中的例子:

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

它不是Java世界中最自然的范例,所以要谨慎使用。虽然泛型方法将使您不必对匹配的值进行类型转换,但我们缺少一种分解匹配对象的标准方法,例如Scala的case类。

While it is not possible to write a switch statement, it is possible to branch out to specific processing for each given type. One way of doing this is to use standard double dispatch mechanism. An example where we want to "switch" based on type is Jersey Exception mapper where we need to map multitude of exceptions to error responses. While for this specific case there is probably a better way (i.e. using a polymorphic method that translates each exception to an error response), using double dispatch mechanism is still useful and practical.

interface Processable {
    <R> R process(final Processor<R> processor);
}

interface Processor<R> {
    R process(final A a);
    R process(final B b);
    R process(final C c);
    // for each type of Processable
    ...
}

class A implements Processable {
    // other class logic here

    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}

class B implements Processable {
    // other class logic here

    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}

class C implements Processable {
    // other class logic here

    <R> R process(final Processor<R> processor){
        return processor.process(this);
    }
}

然后在任何需要“开关”的地方,你可以这样做:

public class LogProcessor implements Processor<String> {
    private static final Logger log = Logger.for(LogProcessor.class);

    public void logIt(final Processable base) {
        log.info("Logging for type {}", process(base));
    }

    // Processor methods, these are basically the effective "case" statements
    String process(final A a) {
        return "Stringifying A";
    }

    String process(final B b) {
        return "Stringifying B";
    }

    String process(final C c) {
        return "Stringifying C";
    }
}

以防万一有人读到

java中的最佳解决方案是:

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

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

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

    };

    abstract void doAction (...);
}

这种模式的最大好处是:

你只需要这样做(完全没有开关): void someFunction (Action Action) { action.doAction(…); } 在这种情况下,如果你添加新的动作称为“d”,你必须实现doAction(…)方法

注意:此模式在Joshua’s Bloch“Effective Java (2nd Edition)”中有描述

不,这是不可能的。然而,您可能想要做的是将多态性作为处理这类问题的一种方法。