我有一个问题,使用开关情况的instanceof对象:
例如:我的问题可以在Java中重现:
if(this instanceof A)
doA();
else if(this instanceof B)
doB();
else if(this instanceof C)
doC():
如何使用switch…case实现它?
我有一个问题,使用开关情况的instanceof对象:
例如:我的问题可以在Java中重现:
if(this instanceof A)
doA();
else if(this instanceof B)
doB();
else if(this instanceof C)
doC():
如何使用switch…case实现它?
当前回答
不幸的是,这是不可能开箱即用的,因为开关case语句需要一个常量表达式。要克服这个问题,一种方法是将枚举值与类名一起使用。
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
}
其他回答
不幸的是,这是不可能开箱即用的,因为开关case语句需要一个常量表达式。要克服这个问题,一种方法是将枚举值与类名一起使用。
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
}
从Java 17开始,您可以对开关表达式(预览特性)JEP-406使用模式匹配。
public void doAction(Object o) {
return switch (o) {
case A a -> doA(a);
case B b -> doB(b);
case C c -> doC(c);
default -> log.warn("Unrecognized type of {}", o);
};
}
防护模式也可用:
public void doAction(Object o) {
return switch (o) {
case String s && !s.isBlank() -> handle(s);
};
}
你需要启用预览功能来使用它:java——enable-preview
如果需要通过“this”对象的类类型“切换”,这个答案是最好的https://stackoverflow.com/a/5579385/2078368
但如果你需要将“switch”应用于任何其他变量。我建议另一种解决办法。定义以下接口:
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;
}
...
}
你唯一需要关心的是——在实现ClassTypeInterface的所有类中保持“类型”的唯一性。这不是一个大问题,因为在任何交集的情况下,您都会收到“switch-case”语句的编译时错误。
Eclipse建模框架有一个有趣的想法,它也考虑了继承。Switch接口中定义了基本概念:通过调用doSwitch方法来完成切换。
真正有趣的是实现。对于每种类型的兴趣,a
public T caseXXXX(XXXX object);
方法必须实现(默认实现返回null)。doSwitch实现将尝试为对象的所有类型层次结构调用所有caseXXX方法。之类的东西:
BaseType baseType = (BaseType)object;
T result = caseBaseType(eAttribute);
if (result == null) result = caseSuperType1(baseType);
if (result == null) result = caseSuperType2(baseType);
if (result == null) result = caseSuperType3(baseType);
if (result == null) result = caseSuperType4(baseType);
if (result == null) result = defaultCase(object);
return result;
实际框架为每个类使用一个整数id,所以逻辑实际上是一个纯切换:
public T doSwitch(Object object) {
return doSwitch(object.class(), eObject);
}
protected T doSwitch(Class clazz, Object object) {
return doSwitch(getClassifierID(clazz), object);
}
protected T doSwitch(int classifierID, Object theObject) {
switch (classifierID) {
case MyClasses.BASETYPE:
{
BaseType baseType = (BaseType)object;
...
return result;
}
case MyClasses.TYPE1:
{
...
}
...
您可以查看ECoreSwitch的完整实现,以获得更好的理解。
你不能。switch语句只能包含case语句,case语句是编译时常量,计算结果为整数(最多Java 6和Java 7中的字符串)。
在函数式编程中,您要寻找的是所谓的“模式匹配”。
参见Java中避免instanceof