Java 方法返回为接口
考虑这个例子: 我有3个接口:A,B,C,方法A(),B(),C();扩展基本接口Intf 我有一个带有选项MyEnum.a、MyEnum.B、MyEnum.C的枚举 我有一个类扩展了这3个接口:X实现了a、B、C 有一种方法可以在X中实现这样的方法Java 方法返回为接口,java,Java,考虑这个例子: 我有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) 或 但从来没有 X var = X.getType(MyEnum.A).b("value").build(); //ERROR 假设我们
public <T extends Intf> T getType (MyEnum enum)
或
但从来没有
X var = X.getType(MyEnum.A).b("value").build(); //ERROR
假设我们在类X中,您有一个本地泛型参数,您可以考虑:
public <T extends Intf> T getType (MyEnum enumVal) {
if (enumVal == MyEnum.A) {
return (A) this;
if (enumVal == MyEnum.B) {
return (B) this;
但你也可以写
B someB = whatever.getType(someEnum);
使用非常相同的someEnum
。编译器会很高兴的
如果您想在“编译时安全性”方面有所收获,您必须以某种方式将参数类型“连接”到结果类型 您可以分派枚举值,并返回一个匹配的实例,正如@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;
}
}
如果我没看错你的问题,你希望编译时安全
public <T extends Intf> T getType (MyEnum enum)
现在,类TT
实现了所有这些接口:
public class TT implements AA, BB, CC {
@Override
public void a() { ... }
@Override
public void b() { ... }
@Override
public void c() { ... }
}
现在让EE
成为我们的通用伪枚举类,用II
的某些子类型参数化:
public interface AA extends II { void a(); }
public interface BB extends II { void b(); }
public interface CC extends II { void c(); }
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>();
}
此方法只能返回参数化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);
}
据我所知,编译器不允许
BB bb = tt.getType(EE.A);
也
不会像“在运行时生成ClassCastException
中那样工作”
缺点是伪枚举构造和
convert
的有些丑陋的实现。我不确定第一个要求:目前我假设baseInterface Intf有3个方法a()、b()和c()。但当我继续阅读时,我不确定是否是这样。请不要解释代码,展示它。请准确地说明您希望如何使用/调用方法getType(…)
。代码最好用最少的代码示例来解释!我猜OP想要getType(MyEnum.A)
返回A
的实例,getType(MyEnum.B)
返回B
的实例等,也就是说,用方法签名来表示。像public T getType(MyEnum)
这样的签名没有意义。签名上写着“无论打电话的人想要什么,我都会退还”。您甚至可以说String s=X.getType(…)
。当然,String
不会实现Intf
,但是可能有一个类型扩展了String
并实现了Intf
,并且您的方法很难实现这个承诺并返回这样一个类型的实例,尤其是String
是final
…我想在一个具有流畅api的构建器上使用它:X.getType(MyEnum.a).a().build()或X.getType(MyEnum.B).B().build(),但永远不要使用X.getType(MyEnum.a).B().build()@marciel.deg,因为这个注释并不能真正阐明您的需求。正如其他人所说:请编辑您的问题,使之更加具体!那些演员对打电话的人来说无关紧要你可以将这个包装成a
、B
或C
的一个新的(匿名内部类)实例,只提供对a()
、B()
或C()
的访问权限。你得到了我的投票支持,同意在这里提出一个想法@AxelH你说得对,我没有注意到A、B、C也是接口。编辑我的答案以提供那些接口的实现,感谢您的提示。但是编译器不会拒绝编写A A=MyEnum.C.getType()
或cc=MyEnum.A.getType()代码>。当泛型代码在运行时甚至不会立即失败时,情况可能会变得更糟,但会导致堆污染、错误类型的实例存储在某个地方,而当没有人知道对象来自何处时,这些实例将在更晚的时间失败。想想Set someMethod(){return Collections.singleton(MyEnum.B.getType());}
…这个答案接近我需要的。@marciel.deg如果你觉得我的答案对你有帮助,你可以。
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>();
}
public <XX extends II> XX getType(EE<XX> enumVal)
AA type = tt.getType(EE.A);
BB type = tt.getType(EE.A);
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);
}
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();