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

在子类(和静态方法)中使用泛型的Java,java,generics,inheritance,Java,Generics,Inheritance,下面是一个简化的示例,可以将此简化为一个问题。有3个类文件(其中有几个类shell)。不起作用的是对SpanTable类中的getTable()和getCreateTableList()中的每一个进行强制转换的第一个参数。我想知道如何使该参数具有其原始的Span/SpanTable子类类型,并传递到DbTable调用中?或者说,DbTable不需要额外的信息,但我希望SpanTable或任何调用者保留其类型 数据库行: public class DbRow { static class

下面是一个简化的示例,可以将此简化为一个问题。有3个类文件(其中有几个类shell)。不起作用的是对
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;
    }
}
import java.util.ArrayList;
抽象公共类DbTable{
静态类对列表{
公共无效补遗(ls,rt){
公共R getRightForLeft(L left){return null;}
}
静态类DbPlatform{}
静态类DbSelectStatement{}
公共静态类Span扩展了DbRow{}
静态类TableList扩展了ArrayList{}
静态类平台列表
扩展成对列表{}
静态DbSelectStatement getDefaultQuery(字符串表名){return null;}
公共数据库表(数据库平台平台,字符串表名){}
public DbSelectStatement getStatement(){return null;}
/**返回匹配的DbTable,其中包含匹配的DbSelectStatement或null*/
静态保护DbTable getTable(
平台列表平台列表,
DbPlatform平台,DbSelectStatement(stmt){
//从列表中获取表,或创建新表
表格列表=
getCreateTableList(
(平台列表)平台列表,平台);
//在列表中搜索匹配项
for(数据库表:列表)
if(table.getStatement().equals(stmt))
返回表;
返回null;
}
/**获取或创建并返回平台的TableList*/
静态保护的TableList getCreateTableList(
平台列表平台列表,DbPlatform平台){
TableList=(TableList)
platformList.getRightForLeft(平台);
if(list==null){
list=新的TableList();
平台列表。附录(平台、列表);
}
退货清单;
}
}
跨度表:

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);
    }
}
类span表扩展了DbTable{
静态私有PlatformTableList platformList=
新平台TableList();
静态公共SpanTable getCreateSpanTable(数据库平台平台,字符串表名){
SpanTable=(SpanTable)可获取(平台列表、平台、,
getDefaultQuery(tableName));
如果(表==null){
表=新的跨度表(平台、表名);
getCreateTableList(平台列表,平台).add(表);
}
返回表;
}
私有span表(DbPlatform平台,字符串tableName){
super(平台、表名);
}
}

您可以将
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;
    }

}

正如在一篇评论中指出的那样:如果您想在
TableList
类中保存特定的行类型
R
,您可以编写
class TableList extensed ArrayList{}
同样,我会尽量避免扩展
ArrayList
,而是创建一个保存
ArrayList
的字段,我不能确切地说出问题出在哪里。你能把问题改写成可编译的状态吗?我的意思是,这不是一个“为什么我不能编译”的问题,而是一个“为什么我必须使用”的问题。@PeterRader现在被组织成3个类文件。@MarkMeyers你不能说
class TableList扩展了ArrayList{}
,因为你必须首先列出所有类型变量。方法是:
classtablelist扩展了ArrayList
@JavierMartín,好的。这似乎奏效了
class TableList扩展了ArrayList{}
,但毫无疑问,键入问题会从那里级联而来。谢谢。这很有效。我很好奇为什么您会避免扩展
ArrayList
?@MarkMeyers一般来说,在使用所讨论的集合时,我更喜欢组合而不是继承。不过,这当然要视情况而定。有时,(可能在您的情况下)扩展
ArrayList
是有意义的,如图所示。
SpanTable<Span> table = getTable(platformList, platform, 
                getDefaultQuery(tableName));