以下是一个清理示例,可将其简化为一个问题。有3个类文件(其中有一些类shell)。不起作用的是将第一个参数强制转换为getTable()类中的getCreateTableList()SpanTable。我想知道如何使该参数具有其原始的Span/SpanTable子类类型并传递给DbTable调用?或实际上,DbTable不需要额外的信息,但我希望SpanTable或任何调用者保留其类型。

DbRow:

public class DbRow {
    static class Span extends DbRow {}
}


DbTable:

import java.util.ArrayList;

abstract public class DbTable<R extends DbRow> {

    static class PairList<L, R> {
        public void addEntry(L s, R t) {  }
        public R getRightForLeft(L left) { return null; }
    }
    static class DbPlatform {  }
    static class DbSelectStatement {    }
    public static class Span extends DbRow { }
    static class TableList<R extends DbRow, T extends DbTable<R>> extends ArrayList<T> {}
    static class PlatformTableList<R extends DbRow, T extends DbTable<R>>
                    extends PairList<DbPlatform, TableList<R, T>> {}
    static DbSelectStatement getDefaultQuery(String tableName) { return null; }

    public DbTable(DbPlatform platform, String tableName) { }
    public DbSelectStatement getStatement() { return null; }

    /** Return the matching DbTable with matching DbSelectStatement or null */
    static protected DbTable<DbRow> getTable(
            PlatformTableList<DbRow, DbTable<DbRow>> platformList,
            DbPlatform platform, DbSelectStatement stmt) {
        // Get the table from the list, or create new
        TableList<DbRow, DbTable<DbRow>> list =
                getCreateTableList(
                 (PlatformTableList<DbRow, DbTable<DbRow>>) platformList, platform);
        // Search the list for a match
        for(DbTable<DbRow> table : list)
            if(table.getStatement().equals(stmt))
                return table;
        return null;
    }

    /** Get or create and return a TableList for the Platform.  */
    static protected TableList<DbRow, DbTable<DbRow>> getCreateTableList(
            PlatformTableList<DbRow, DbTable<DbRow>> platformList, DbPlatform platform) {

        TableList<DbRow, DbTable<DbRow>> list = (TableList<DbRow, DbTable<DbRow>>)
                platformList.getRightForLeft(platform);
        if(list == null) {
            list = new TableList<DbRow, DbTable<DbRow>>();
            platformList.addEntry(platform, list);
        }
        return list;
    }
}


跨度表:

class SpanTable<R extends DbTable.Span> extends DbTable<R> {

    static private PlatformTableList<Span, SpanTable<Span>> platformList =
            new PlatformTableList<Span, SpanTable<Span>>();

    static public SpanTable<Span> getCreateSpanTable(DbPlatform platform, String tableName) {

        SpanTable<Span> table = (SpanTable<Span>) getTable(platformList, platform,
                getDefaultQuery(tableName));
        if(table == null) {
            table = new SpanTable<Span>(platform, tableName);
            getCreateTableList(platformList, platform).add(table);
        }
        return table;
    }

    private SpanTable(DbPlatform platform, String tableName) {
        super(platform, tableName);
    }
}

最佳答案

您可以使DbTable类内部的工厂方法通用,以便它们保留通过平台列表传递给它们的特定表类型(T):

abstract public class DbTable<R extends DbRow> {

    protected DbTable(DbPlatform platform, String tableName) {  }

    static class TableList<T extends DbTable<?>> extends ArrayList<T> {}

    static class PlatformTableList<T extends DbTable<?>>
                    extends PairList<DbPlatform, TableList<T>> {}

    /** Return the matching DbTable with matching DbSelectStatement or null.
     * Will create/add a new TableList if platform not found. */

    static protected <T extends DbTable<?>> T getTable(PlatformTableList<T> platformList,
            DbPlatform platform, DbSelectStatement stmt) {

        // Get the table from the list, or create new
        TableList<T> list = getCreateTableList(platformList, platform);
        // Search the list for a match
        for(T table : list) {
            if(table.equals(stmt))
                return table;
        }
        return null;
    }

    /** Get or create and return a TableList for the Platform.  */
    static protected <T extends DbTable<?>> TableList<T> getCreateTableList(
            PlatformTableList<T> platformList, DbPlatform platform) {

        TableList<T> list = platformList.getRightForLeft(platform);
        if(list == null) {
            list = new TableList<T>();
            platformList.addEntry(platform, list);
        }
        return list;
    }

}


现在,您还可以在getCreateSpanTable()方法中删除强制类型转换:

SpanTable<Span> table = getTable(platformList, platform,
                getDefaultQuery(tableName));


正如评论中指出的那样:如果要在R类中保留特定的行类型TableList,则可以编写class TableList<R extends DbRow, T extends DbTable<R>> extends ArrayList<T> {}。此外,我会尽量避免扩展ArrayList并创建一个包含ArrayList代替。

10-05 23:32