在java中切换类型

ewo*_*wok 27 java enums types instanceof switch-statement

在开始之前,我知道这个问题有很多答案可以提出替代方法.我正在寻求这种特殊方法的帮助,以确定是否可行,如果不可能,可能会有类似的方法.

我有一个方法,它接受一个超类并根据传递的对象的类型调用一个方法.例如:

public void handle(Object o){
  if (o instanceof A)
    handleA((A)o);
  else if (o instanceof B)
    handleB((B)o);
  else if (o instanceof C)
    handleC((C)o);
  else 
    handleUnknown(o);
Run Code Online (Sandbox Code Playgroud)

我不能修改子类型来覆盖一个handle()方法,正如这个答案所暗示的那样,因为我不拥有这些类.所以这个instanceof方法就是我所拥有的.

我想用一个switch声明代替if/else,只是因为它更整洁.我知道你只能打开基元和字符串,所以我要切换类名:

switch(o.getClass().getCanonicalName()){
case "my.package.A":
  handleA((A)o);
  break;
case "my.package.B":
  handleB((B)o);
  break;
case "my.package.C":
  handleC((C)o);
  break;
default:
  handleUnknown(o);
  break;
}
Run Code Online (Sandbox Code Playgroud)

这里的问题是规范名称非常长(如12个子包),我不能调用ClassName.class.getCanonicalName()case语句,因为Java不允许这样做.所以我的下一个解决方案是Enum.这是我遇到问题的地方.

我希望我的代码看起来像这样:

public enum Classes {
  A (A.getCanonicalName()),
  B (B.getCanonicalName()),
  C (C.getCanonicalName());
}

switch (o.getClass().getCanonicalName()){
case Classes.A:
  handleA((A)o);
  break;
case Classes.B:
  handleB((B)o);
  break;
case Classes.C:
  handleC((C)o);
  break;
default:
  handleUnknown(o);
  break;
}
Run Code Online (Sandbox Code Playgroud)

但这不编译.我不知道为什么.我想要一些允许我切换类型而不必输入整个规范名称的方法.如果我这样做,我不妨只使用if/elseinstanceof.

注意有几种类型具有相同的名称(内部类),因此getSimpleName()也是如此.

das*_*ght 30

这是一种根本不处理类名的方法,并且调度与switch语句一样快:创建哈希映射以将Class<T>对象映射到特定于类的处理程序,并使用映射而不是switch:

// Declare an interface for your polymorphic handlers to implement.
// There will be only anonymous implementations of this interface.
private interface Handler {
    void handle(Object o);
}
// Make a map that translates a Class object to a Handler
private static final Map<Class,Handler> dispatch = new HashMap<Class,Handler>();
// Populate the map in a static initializer
static {
    dispatch.put(A.class, new Handler() {
        public void handle(Object o) {
            handleA((A)o);
        }
    });
    dispatch.put(B.class, new Handler() {
        public void handle(Object o) {
            handleB((B)o);
        }
    });
    dispatch.put(C.class, new Handler() {
        public void handle(Object o) {
            handleC((C)o);
        }
    });
}
// This object performs the dispatch by looking up a handler,
// and calling it if it's available
private static void handle(Object o) {
    Handler h = dispatch.get(o.getClass());
    if (h == null) {
        // Throw an exception: unknown type
    }
    h.handle(o); // <<== Here is the magic
}
Run Code Online (Sandbox Code Playgroud)

  • @AndyThomas和OP的`switch`语句一样:) (3认同)
  • 使用Java 8 lambda或方法引用,您可以使其更加简洁(不需要所有匿名的“ Handler”子类)。 (2认同)

eit*_*tan 24

使用java 8 lambdas你可以得到这样的东西:

Collection col = Arrays.asList(1,2,3);
switchType(col, 
       caze(Collection.class, c->System.out.println(c.size())),
       caze(ArrayBlockingQueue.class, bq->System.out.println(bq.remainingCapacity())),
       caze(Queue.class, q->System.out.println(q.poll())),
       caze(String.class, s->System.out.println(s.substring(0))),
       caze(ArrayList.class, al->System.out.println(al.get(0)))
);
Run Code Online (Sandbox Code Playgroud)

为此,您应该定义以下静态方法:

public static <T> void switchType(Object o, Consumer... a) {
    for (Consumer consumer : a)
        consumer.accept(o);
}

public static <T> Consumer caze(Class<T> cls, Consumer<T> c) {
    return obj -> Optional.of(obj).filter(cls::isInstance).map(cls::cast).ifPresent(c);
}    
Run Code Online (Sandbox Code Playgroud)

  • @Francy,您可以使用函数而不是使用者. (4认同)
  • 不错,但是如何“打破”我的意思是,如果第一个比赛叫了,然后退出“消费者” (2认同)
  • 这增加了很多永恒 (2认同)

A_A*_*old 19

Java 目前有一个草案来支持这一点。见这里。语法看起来像这样

switch (obj) {
    case Integer i: handleI(i); break;
    case Byte b:    handleB(b); break;
    case Long l:    handleL(l); break;
    case Double d:  handleD(d); break;
    case String s:  handleS(s); break
    default:        handle(obj);
}
Run Code Online (Sandbox Code Playgroud)