问题描述
假设我有以下两个接口:
接口Processor {
void process(Foo foo);
}
interface Foo {
处理器getProcessor();
}
以及以下两个实现类:
静态类SomeProcessor实现处理器{
static final SomeProcessor INSTANCE = new SomeProcessor();
@Override
public void process(Foo foo){
if(foo instanceof SomeFoo){//< - GET RID OF THIS?
//进程((SomeFoo)foo)
}
}
}
类SomeFoo实现Foo {
@Override
公共处理器getProcessor(){
返回SomeProcessor.INSTANCE;
$ b 有没有办法使这两个接口通用这样我不需要在 process()
函数中标记 instanceof
检查并仍然具有以下在我的代码的其他地方构建工作?
foo.getProcessor()。process(foo);
(当然,我不知道我正在处理的Foo的子类)换句话说:我正在寻找一种方法来定义一个对象中的函数,以便它只能返回另一个对象,该对象处理包含该对象的类型功能。注意:我不只是在谈论如何处理包含该函数的对象的最小公分母超类(上图:Foo),而是该对象的实际类(上面的:SomeFoo)。
(这可能听起来毫无意义,除非我现在真的很愚蠢......)
解决方案这比我想象的更丑陋。我的看法:
接口处理器< F extends Foo< F>> {
void process(F foo);
}
interface Foo< F extends Foo< F>> {
处理器< F> getProcessor();
}
接口SomeFoo扩展Foo< SomeFoo> {
@Override
SomeProcessor getProcessor();
}
接口SomeProcessor扩展Processor< SomeFoo> {
@Override
void process(SomeFoo foo);
}
现在,以下代码将被编译:
< F extends Foo< F>> void process(F foo){
foo.getProcessor()。process(foo);
但是
<$ p ($ f $ f $ f $ f $)$ f $。
}
不会,因为编译器无法知道传入的实际类型foo是其类型参数的子类型,因为有人可以这样写:
class Bar实现Foo< SomeFoo> {...}
我们可以通过要求foo的子类实现转换它们的类型参数:
pre $ abstract class Foo< F extends Foo< F>> {
抽象处理器< F> getProcessor();
abstract F getThis();
}
类SomeFoo扩展Foo< SomeFoo> {
@Override
SomeFoo getThis(){
return this;
}
@覆盖
处理器< SomeFoo> getProcessor(){
return new SomeProcessor();
$ / code $ / pre
现在,我们可以这样写:
< F extends Foo< F>> void process(Foo< F> foo){
foo.getProcessor()。process(foo.getThis());
}
并用
调用 富<?> foo = ...;
process(foo);
为了便于使用,我建议将辅助方法移入Foo类中:
抽象类Foo< F extends Foo< F>> {
抽象处理器< F> getProcessor();
abstract F getThis();
void processWith(Processor< F> p){
p.process(getThis());
$ / code>
更新:我认为newaccts更新的答案显示更优雅解决方案,因为它不需要递归类型边界。
Got a little puzzle for a true Java Generics specialist... ;)
Let's say I have the following two interfaces:
interface Processor {
void process(Foo foo);
}
interface Foo {
Processor getProcessor();
}
and, for example, the following two implementing classes:
static class SomeProcessor implements Processor {
static final SomeProcessor INSTANCE = new SomeProcessor();
@Override
public void process(Foo foo) {
if (foo instanceof SomeFoo) { // <-- GET RID OF THIS ?
// process ((SomeFoo) foo)
}
}
}
class SomeFoo implements Foo {
@Override
public Processor getProcessor() {
return SomeProcessor.INSTANCE;
}
}
Is there some way to make the two interfaces generic in such a way that I don't need the marked instanceof
check in the process()
function and still have the following construct work elsewhere in my code?
foo.getProcessor().process(foo);
(where, of course, I don't know what subclass of Foo I'm dealing with)
In other words: I'm looking for a way to define a function in an object such that it can only return another object that processes the type of object that contained the function. Note: I'm not just talking about processing some least common denominator super-class of the object containing the function (above: Foo), but that object's actual class (above: SomeFoo).
(This is nowhere near as trivial as it may sound unless I'm really being stupid right now...)
This is uglier than I thought. My take:
interface Processor<F extends Foo<F>> {
void process(F foo);
}
interface Foo<F extends Foo<F>> {
Processor<F> getProcessor();
}
interface SomeFoo extends Foo<SomeFoo> {
@Override
SomeProcessor getProcessor();
}
interface SomeProcessor extends Processor<SomeFoo> {
@Override
void process(SomeFoo foo);
}
Now, the following will compile:
<F extends Foo<F>> void process(F foo) {
foo.getProcessor().process(foo);
}
but
void process(Foo<?> foo) {
foo.getProcessor().process(foo);
}
doesn't, because the compiler can not know that actual type of the passed foo is a subtype of its type parameter, as somebody could write:
class Bar implements Foo<SomeFoo> { ... }
We can work around this by requiring the subtypes of foo to implement a conversion to their type parameter:
abstract class Foo<F extends Foo<F>> {
abstract Processor<F> getProcessor();
abstract F getThis();
}
class SomeFoo extends Foo<SomeFoo> {
@Override
SomeFoo getThis() {
return this;
}
@Override
Processor<SomeFoo> getProcessor() {
return new SomeProcessor();
}
}
Now, we can write:
<F extends Foo<F>> void process(Foo<F> foo) {
foo.getProcessor().process(foo.getThis());
}
and invoke this with
Foo<?> foo = ...;
process(foo);
To make it easy to use, I recommend moving the helper method into class Foo:
abstract class Foo<F extends Foo<F>> {
abstract Processor<F> getProcessor();
abstract F getThis();
void processWith(Processor<F> p) {
p.process(getThis());
}
}
Update: I think newaccts updated answer shows a more elegant solution, as it does not need the recursive type bounds.
这篇关于如何用编译时泛型验证替换运行时instanceof检查的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!