键入安全性,Java泛型和查询

Mic*_*ler 10 java generics

我有一个有趣的情况,我想知道是否有更好的方法来做到这一点.情况是这样的,我有一个树结构(具体是抽象语法树),一些节点可以包含各种类型的子节点,但都从给定的基类扩展.

我想经常在这个树上做查询,我想找回我感兴趣的特定子类型.所以我创建了一个谓词类,然后我可以将其传递给通用查询方法.起初我有一个看起来像这样的查询方法:

public <T extends Element> List<T> findAll(IElementPredicate pred, Class<T> c);
Run Code Online (Sandbox Code Playgroud)

其中Class参数仅用于指示返回类型.令我困扰的是这种方法是我的所有谓词都已经用于特定类型,所以这里有冗余信息.典型的呼叫可能如下所示:

List<Declaration> decls = 
    scope.findAll(new DeclarationPredicate(), Declaration.class);
Run Code Online (Sandbox Code Playgroud)

所以我像这样重构它:

public <T extends Element> List<T> findAll(IElementPredicate<T> pred);
Run Code Online (Sandbox Code Playgroud)

IElementPredicate界面看起来是这样的:

public interface IElementPredicate<T extends Element> {
    public boolean match(T e);
    public String getDescription();
    public Class<T> getGenericClass();
}
Run Code Online (Sandbox Code Playgroud)

这里的要点是谓词接口被扩展以提供Class对象.它使得编写实际的findAll方法更加有效,并且它在编写谓词时增加了一些工作,但这些都是微小的"一次性"事情,它使查询调用更好,因为你没有添加额外的(可能是多余的)参数,例如

List<Declaration> decls = scope.findAll(new DeclarationPredicate());
Run Code Online (Sandbox Code Playgroud)

我之前没有注意到这种模式.这是处理Java泛型语义的典型方法吗?只是好奇我是否错过了一些更好的模式.

Commments?

更新:

一个问题是你需要什么类?这是findAll的实现:

public <T extends Element> List<T> findAll(IElementPredicate<T> pred) {
    List<T> ret = new LinkedList<T>();
    Class<T> c = pred.getGenericClass();
    for(Element e: elements) {
        if (!c.isInstance(e)) continue;
        T obj = c.cast(e);
        if (pred.match(obj)) {
            ret.add(c.cast(e));
        }
    }
    return ret;
}
Run Code Online (Sandbox Code Playgroud)

虽然匹配只需要一个T,但我需要确保该对象是一个T才能调用它.为此,我需要Class的"isInstance"和"cast"方法(据我所知).

Yar*_*ena 1

我认为最接近的“模式”是类型标记,泛型教程推荐它们。您还可以将基本谓词转换为超级类型令牌(又名 Gafter 小工具),并在定义新谓词时节省额外的几行。