Switch instanceof?

匿名 (未验证) 提交于 2019-12-03 02:00:02

问题:

I have a question of using switch case for instanceof object:

For example: my problem can be reproduced in Java:

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

How would it be implemented using switch...case?

回答1:

This is a typical scenario where subtype polymorphism helps. Do the following

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

Then you can simply call do() on this.

If you are not free to change A, B, and C, you could apply the visitor pattern to achieve the same.



回答2:

if you absolutely cannot code to an interface, then you could use an enum as an intermediary:

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


回答3:

Just in case if someone will read it:

The BEST solution in java is :

public enum Action {      a{         void doAction(...){             // some code         }      },      b{         void doAction(...){             // some code         }      },      c{         void doAction(...){             // some code         }      };      abstract void doAction (...); } 

The GREAT benefits of such pattern are:

  1. You just do it like (NO switches at all):

    void someFunction ( Action action ) {     action.doAction(...);    } 
  2. In case if you add new Action called "d" you MUST imlement doAction(...) method

NOTE: This pattern is described in Joshua's Bloch "Effective Java (2nd Edition)"



回答4:

You can't. The switch statement can only contain case statements which are compile time constants and which evaluate to an integer (Up to Java 6 and a string in Java 7).

What you are looking for is called "pattern matching" in functional programming.

See also Avoiding instanceof in Java



回答5:

As discussed in the top answers, the traditional OOP approach is to use polymorphism instead of switch. There is even a well documented refactoring pattern for this trick: Replace Conditional with Polymorphism. Whenever I reach for this approach, I like to also implement a Null object to provide the default behaviour.

Starting with Java 8, we can use lambdas and generics to give us something functional programmers are very familiar with: pattern matching. It's not a core language feature but the Javaslang library provides one implementation. Example from the javadoc:

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

It's not the most natural paradigm in the Java world so use it with caution. While the generic methods will save you from having to typecast the matched value, we're missing a standard way to decompose the matched object as with Scala's case classes for example.



回答6:

Just create a Map where the class is the key and the functionality, i.e. lambda or similar, is the value.

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

// of course, refactor this to only initialize once

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

If you need checked Exceptions than implement a FunctionalInterface that throws the Exception and use that instead of Runnable.



回答7:

Nope, there is no way to do this. What you might want to do is however to consider Polymorphism as a way to handle these kind of problems.



回答8:

Using switch statements like this is not the object oriented way. You should instead use the power of polymorphism. Simply write

this.do() 

Having previously set up a base class:

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

which is the base class for A, B and 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() } } 


回答9:

I know this is very late but for future readers ...

Beware of the approaches above that are based only on the name of the class of A, B, C ... :

Unless you can guarantee that A, B, C ... (all subclasses or implementers of Base) are final then subclasses of A, B, C ... will not be dealt with.

Even though the if, elseif, elseif .. approach is slower for large number of subclasses/implementers, it is more accurate.



回答10:

You can't a switch only works with the byte, short, char, int, String and enumerated types (and the object versions of the primitives, it also depends on your java version, Strings can be switched on in java 7)



回答11:

How about this ?

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


回答12:

If you can manipulate the common interface, you could do add in an enum and have each class return a unique value. You won't need instanceof or a visitor pattern.

For me, the logic needed to be in the written in the switch statement, not the object itself. This was my solution:

ClassA, ClassB, and ClassC implement CommonClass

Interface:

public interface CommonClass {    MyEnum getEnumType(); } 

Enum:

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

If you are on java 7, you can put string values for the enum and the switch case block will still work.



回答13:

If you need to "switch" thru the class type of "this" object, this answer is the best https://stackoverflow.com/a/5579385/2078368

But if you need to apply "switch" to any other variable. I would suggest another solution. Define following interface:

public interface ClassTypeInterface {     public String getType(); } 

Implement this interface in every class you want to "switch". Example:

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

After that you can use it in following way:

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

The only thing you should care about - keep the "types" unique across all the classes implementing the ClassTypeInterface. It's not a big problem, because in case of any intersection you receive a compile-time error for the "switch-case" statement.



回答14:

there is an even simpler way of emulating a switch structure that uses instanceof, you do this by creating a code block in your method and naming it with a label. Then you use if structures to emulate the case statements. If a case is true then you use the break LABEL_NAME to get out of your makeshift switch structure.

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


回答15:

I personally like the following Java 1.8 code:

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

Will output:

YYyy 

The sample code uses Strings but you can use any object type, including Class. e.g. .myCase(this.getClass(), (o) -> ...

Needs the following snippet:

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


回答16:

I think there are reasons to use a switch statement. If you are using xText generated Code perhaps. Or another kind of EMF generated classes.

instance.getClass().getName(); 

returns a String of the Class Implementation Name. i.e: org.eclipse.emf.ecore.util.EcoreUtil

instance.getClass().getSimpleName(); 

returns the simple represenation i.e: EcoreUtil



文章来源: Switch instanceof?
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!