如何用泛型限制对象创建?

时间:2011-04-28 13:39:14

标签: java generics

我希望有一个类型层次结构,其中只有Foo个对象可以控制Bar个对象的创建。 E.g:

public abstract class Foo<F extends Foo<F>> {
    public abstract  Bar<F> makeBar();
}

public abstract class Bar<F extends Foo<F>> {}

现在,Foo的子类可以实现Bar的子类并将其返回:

public class FooImpl extends Foo<FooImpl> {

    private static class BarImpl extends Bar<FooImpl> {}

    @Override
    public Bar<FooImpl> makeBar() { return new BarImpl(); }
}

然而,这仍然允许在其他地方创建Bar

public class FakeBar extends Bar<FooImpl> {}

如何限制Bar<FooImpl>(仅使用类型系统,而不是运行时检查)以{strong>必须由FooImpl的实例创建,并且< strong>不能在其他任何地方创建?

4 个答案:

答案 0 :(得分:1)

这不起作用(限制:仅限类型系统,没有运行时检查)。我们可以禁止一般的子类化(final类)或允许它。如果(公共)类不是final类,则任何其他类都可以是子类。

您可以尝试使用注释 - 例如发明注释,列出允许的类名,但这取决于处理注释。

示例:

@AllowedSubclasses(classnames="com.example.FooBar; *.AnyFooBar; com.example.foobars.*")
public abstract class Bar<F extends Foo<F>> {}

如果任何其他类为这个带注释的类创建子类,则注释处理器会抛出错误。


混合方法怎么样:在javaDoc和文档中用“HANDS OFF”注释你的内部方法,任何违规都会导致运行时异常。调用该方法后,您可以在该方法中验证调用者是否是允许使用此功能的其中一个类的实例。

答案 1 :(得分:1)

这不是类型系统可以(或应该)做的事情。您想要访问限制,请使用Java的访问修饰符。但我不认为那些可以实现您非常具体和不寻常的要求。

实际上,我认为它们根本不可以实现:你希望一个类可以公开显示而且不是最终的,但是允许调用它的构造函数来扩展它到特定的类及其子类?

对不起,没有办法。无论如何,这有什么意义呢?

答案 2 :(得分:0)

您可以使makeBar成为调用实际创建的protected abstract makeBar0的具体方法。 makeBar()可以获取结果并以任何方式检查对象。

public abstract class Foo<F extends Foo<F>> {
    public Bar<F> makeBar() {
        Bar<F> bar = makeBar0();
        // check bar
        return bar;
    }
}

如果您愿意,可以添加一个Foo创建的检查,这可能会提高性能。即检查makeBar0();

的返回类型

答案 3 :(得分:0)

不是依赖于泛型等,更简单的方法是强制要求Foo的实例创建Bar

public Bar(Foo foo){...}

这样,没有人可以独立于Foo创建一个栏。这将两个类联系起来,并向用户表明这一事实。还有其他方法可以实现这一点......这只是一个例子