首页 > 解决方案 > Java:返回一个实现具有类型推断的接口的类

问题描述

第一次发帖,抱歉标题可能是垃圾。我正在尝试使用类型推断,但在使用工厂模式时努力使其正常工作,让我抛出一些代码以使其更清晰:

private class ParentObject { }

private class ChildObject extends ParentObject { }

private interface Template<T extends ParentObject> {
    void doSomething(T object);
}

private class TemplateImpl implements Template<ChildObject> {
    public void doSomething(ChildObject object) { }
}

所以我有一些继承自 Template 的类,它们对继承自 ParentObject 的对象做一些事情(我在这篇文章中只发布了一个)。现在我遇到的这个问题是,当我尝试生成这些模板类之一时,当我尝试执行此操作时,我不断收到“不兼容的类型”错误:

private class Factory {
    public <T extends ParentObject> Template<T> generate() {
        return new TemplateImpl(); // here is the error
    }
}
private class Service {
    public <T extends ParentObject> void magic() {
        Factory f = new Factory();
        Template<T> a = f.generate();
    }
}

或者我收到“未经检查的分配”警告(代码按预期工作,但如果我做错了什么,我宁愿修复它!)当我这样做时:

private class AlternativeFactory {
    public Template generate() {
        return new TemplateImpl();
    }
}
private class Service {
    public <T extends ParentObject> void magic() {
        AlternativeFactory af = new AlternativeFactory();
        Template<T> b = af.generate(); // warning here
    }
}

有没有人对我如何在没有任何警告的情况下完成这项工作有任何见解?如果这是一个简单的推理,我没有太多使用类型推理!我不明白的是为什么我不能将 TemplateImpl 作为模板返回,因为它实现了模板?

谢谢!

编辑:事实上,我想要实现的工厂看起来像这样,这似乎是类型推断问题所在:

private class Factory {
    public Template<T extends ParentObject> generate(int option) {
        switch (option) {
            case 1:
                return new TemplateA(); // implements Template<A> where A extends ParentObject
            case 2:
                return new TemplateB(); // implements Template<B> where B extends ParentObject
            default:
                throw new IllegalArgumentException();
        }
    }
}

编辑:决定使用我上面提供的代码(AlternativeFactory),并在调用工厂的服务方法中使用 SuppressWarnings,因为看起来我希望实现的目标是不可能的。我知道这使用原始类型并且是不好的做法,但是我围绕这些模板对象和 AlternativeFactory 进行了很多测试,包括类型检查,所以现在必须这样做。

标签: javatype-inferenceinference

解决方案


TemplateImpl仅与 兼容Template<ChildObject>,因此new TemplateImpl()不能是 - 的有效返回值,public <T extends ParentObject> Template<T> generate()因为T可以是 的不同子类ParentObject

最简单的更改是创建Template一个类:

private class Template<T extends ParentObject> {
    void doSomething(T object){/*implement*/}
}

或者,如果它必须是一个接口,也可以TemplateImpl通用:

private class TemplateImpl<T extends ParentObject> implements Template<T> {
    public void doSomething(ChildObject object) { }
}

这将允许您的工厂使用类型参数:

private class Factory {
    public <T extends ParentObject> Template<T> generate() {
        return new TemplateImpl<T>(); //T is not bound to ChildObject
    }
}

如果您只需要确保它TemplateImpl仅作为 工作Template<ChildObject>,那么您的工厂方法不需要是通用的:

private class TemplateImpl implements Template<ChildObject> {
    public void doSomething(ChildObject object) { }
}

//and the factory:
private class Factory {
    public Template<ChildObject> generate() {
        return new TemplateImpl(); //TemplateImpl is a Template<ChildObject>
    }
}

应该避免您的第二种解决方案,因为它使用原始类型。


推荐阅读