在子类化(和静态方法)中使用泛型的 Java

标签 java generics inheritance

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

数据库行:

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

数据库表:

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 的字段相反。

关于在子类化(和静态方法)中使用泛型的 Java,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42353140/

相关文章:

java - 创建一个方法来处理所有类型的 Swing 组件

java - 如何在Java中打印以逗号作为千位分隔符的自然数?

c# - 将泛型传递给扩展方法

c# - 使用实现而不是抽象或更改实现是否正确?

java - 仅从 @ManyToOne 关系中获取一列

c# - 通用 Web Api 方法

java - 扩展泛型类时如何传递多个泛型参数

c++ - 界面的解决方法

java - 在java方法重写中使用通配符

java - 如果调用位于 try/catch block 中并且该方法也抛出异常,那么 catch 是否具有优先级?