考虑以下示例:
我有3个接口:A,B,C,使用方法a(),b(),c();扩展基本接口Intf;
我有一个带有MyEnum.A,MyEnum.B,MyEnum.C选项的枚举;
我有一个扩展这3个接口的类:X实现A,B,C;
有一种方法可以在X中实现这样的方法;
public <T extends Intf> T getType (MyEnum enum)
结果是接口A,B或C,即仅访问方法a(),b()或c()?
编辑:我想在具有流畅api的构建器上使用它:
X var = X.getType(MyEnum.A).a("value").build();
或
X var = X.getType(MyEnum.B).b("value").build();
但从不
X var = X.getType(MyEnum.A).b("value").build(); //ERROR
答案 0 :(得分:2)
您可以分派枚举值,并按照@GhostCat的建议返回匹配的实例。
您还可以反转查询,因此每个枚举值都提供Intf
的适当实例:
变量1 :每个枚举值的单例实例
public enum MyEnum {
A(new AImpl()),
B(new BImpl()),
C(new CImpl());
private Intf instance;
MyEnum2(Intf instance) {
this.instance = instance;
}
public <T extends Intf> T getType() {
return (T) instance;
}
}
变体2 :工厂,创建新实例:
public enum MyEnum {
A(AImpl.class),
B(BImpl.class),
C(CImpl.class);
private Class<? extends Intf> type;
MyEnum(Class<? extends Intf> type) {
this.type = type;
}
public <T extends Intf> T getType() {
try {
return (T) type.newInstance();
} catch (InstantiationException | IllegalAccessException ex) {
throw new RuntimeException(ex.getMessage(), ex);
}
}
}
用法:
A a = MyEnum.A.getType();
B b = MyEnum.B.getType();
C c = MyEnum.C.getType();
答案 1 :(得分:1)
如果我正确阅读了您的问题,则需要
的编译时安全性public <T extends Intf> T getType (MyEnum enum)
为A
返回MyEnum.A
,为B
返回MyEnum.B
,等等。
如果使MyEnum
类通用,则可以实现此编译时安全性。现在,此方法适用于普通枚举,但适用于老式的“类型安全枚举”模式。
假设我们有三个接口AA
,BB
和CC
扩展了基本接口II
:
public interface AA extends II { void a(); }
public interface BB extends II { void b(); }
public interface CC extends II { void c(); }
现在类TT
实现所有这些接口:
public class TT implements AA, BB, CC {
@Override
public void a() { ... }
@Override
public void b() { ... }
@Override
public void c() { ... }
}
现在让EE
为我们的通用伪枚举类,并使用II
的某些子类型进行参数化:
public class EE<XX extends II> {
public static final EE<AA> A = new EE<AA>();
public static final EE<BB> B = new EE<BB>();
public static final EE<CC> C = new EE<CC>();
}
使用这些定义,getType
方法可以声明如下:
public <XX extends II> XX getType(EE<XX> enumVal)
此方法只能返回参数化enumVal
的类型的类型。含义
AA type = tt.getType(EE.A);
有效,但
BB type = tt.getType(EE.A);
不是。
实现getType
方法的一种方法是将TT
实例的“转换”委托给AA
,BB
或CC
到对应的伪枚举:
public abstract class EE<XX extends II> {
public static final EE<AA> A = new EE<AA>() {
@Override
public <PP extends AA & BB & CC> AA convert(PP instance) {
return new AA() {
public void a() {
instance.a();
};
};
}
};
public static final EE<BB> B = new EE<BB>() {
@Override
public <PP extends AA & BB & CC> BB convert(PP instance) {
return new BB() {
public void b() {
instance.b();
};
};
}
};
public static final EE<CC> C = new EE<CC>() {
@Override
public <PP extends AA & BB & CC> CC convert(PP instance) {
return new CC() {
public void c() {
instance.c();
};
};
}
};
public abstract <PP extends AA & BB & CC> XX convert(PP instance);
}
您也可以直接返回instance
,而无需包装在匿名内部类中。但是随后可以将结果强制广播到其他接口,从而允许访问其他方法。
最后,getType
的实现很简单:
public <XX extends II> XX getType(EE<XX> enumVal) {
return enumVal.convert(this);
}
据我所知,编译器不允许
BB bb = tt.getType(EE.A);
也
BB bb = (BB) tt.getType(EE.A);
bb.b();
无法像“在运行时生成ClassCastException
时那样工作。
缺点是伪枚举构造和convert
的实现有点难看。
答案 2 :(得分:0)
假设我们在类X中,那么您有一个本地通用参数,您可能会想到:
public <T extends Intf> T getType (MyEnum enumVal) {
if (enumVal == MyEnum.A) {
return (A) this;
if (enumVal == MyEnum.B) {
return (B) this;
但是您这样做没有任何收获。这些转换对调用方来说无关紧要。
因为在这里编译器无法为您做任何事情。你可以写
A someA = whatever.getType(someEnum);
但是你也可以写
B someB = whatever.getType(someEnum);
具有相同的someEnum
。而且编译器会很高兴。
如果要获得“编译时安全性”的好处,则必须以某种方式将参数类型“连接”到结果类型。