Java - 如何创建调用接口方法的泛型类?

时间:2015-09-11 17:09:14

标签: java generics interface

我有一个返回JSON实体列表的API,例如GeneProteinResource等。例如,Protein端点返回:

{
    next: "/api/1.0/protein?cursor=200",
    entities: [
    {
        symbol: "TARSH_HUMAN",
        href: "/api/1.0/protein/TARSH_HUMAN"
    },
    {
        symbol: "ABL1_HUMAN",
        href: "/api/1.0/protein/ABL1_HUMAN"
    },
    ...

Resource端点完全相同,但symbolname除外。

到目前为止

解决方案

我想做的是创建某种EntityListSchema,无论实体是什么,都可以生成这样的列表。这就是我所拥有的:

public class EntityListSchema<T extends JsonModel> {

    private String next;

    private List<T> entities;

    public EntityListSchema(Class<T> klass, int startAt) {
        int nextInt = startAt + Constant.API_MAX_RESULTS;
        this.next = "/" 
            + Constant.API_URL + "/"
            + klass.getEndpoint() + "?" // <-- This is the problem
            + Constant.API_CURSOR + "=" + nextInt;
    }

    ...

原则上,每个Entity只能扩展JsonModel以确保getEndpoint可用,我们就完成了。但我看到了错误:

  

类型Class&lt; T&gt;

的方法getEndpoint()未定义

我的理解是发生此错误是因为方法getEndpoint不是静态的。但如果它是静态的(我使用的是Java 8,那么我可以使用静态接口)我根据类不能返回正确的端点。

有可能实现我想要的吗?这将减少大量的重复代码。

3 个答案:

答案 0 :(得分:2)

您会混淆对象实例及其类,例如对于字符串,String.class是类(您的Class<T>)而"foobar"是一个实例(您的T列表中的元素),在此示例中,只有"foobar"具有String方法,String.class具有Class方法。

我的建议是在这里使用一些注释来定义“端点”,然后使用Class#getAnnotation

答案 1 :(得分:2)

您在班级的a:hover + .user-image li { display: block; } Java Class之间感到困惑,

是定义。 该类的实例是实现。

Instance

表示Class<T> klass ,它不代表对象ClassT的实例,它代表T本身,带有te变量名,类名称,方法名称,但没有他的实现:

请参阅:Class java

您需要仅使用Class

而不是Class<T>

了解有关java generics

的更多信息

这是你的代码:

T

答案 2 :(得分:1)

public EntityListSchema(Class<T> klass, int startAt) {
...
    + klass.getEndpoint() 

所以kclass可以是GeneProtein等。所有Protein个实例共享相同的endpoint,因此您想要调用klass.getEndpoint }。

但是:已清除的Class<T>类型为Class,但没有此方法。您真的在寻找一个不存在的 static virtual 方法。

有几种方法可以解决这个问题:registry pattern是一种选择;关于班级的注释是另一个在另一个答案中解释的。

但在您的情况下使用instance method本身可能最简单,假设您this.next仅在this.entities不为空时才需要this.next。如果您延迟分配getEndpoint,那么您可以将class JsonModel { abstract String getEndpoint(); ... } ... public EntityListSchema(List<T> entities, int startAt) { this.entities = entities; if (!entities.empty()) { int nextInt = startAt + Constant.API_MAX_RESULTS; this.next = "/" + Constant.API_URL + "/" + entities.get(0).getEndpoint() + "?" // <-- This is the problem + Constant.API_CURSOR + "=" + nextInt; } 声明为实例方法,并且可以从此列表中的第一个元素中获取其值。或者,您可以使用列表本身进行初始化:

header {
    width: 100%;
    padding-top: 10px;
    padding-right: 10px;
    padding-bottom: 10px;
    position: fixed;
    top: 10px;
    left: 0px;
    right: 0px;
    height: 55px;
    border-bottom: 4px solid #636466;
    margin-bottom: 10px;
    margin-top: 0px;
}
#logo  {
    float: left;
    background-image: url(wordsbyperla_wordpress%20header_small.png);
    background-repeat: no-repeat;
    height: 50px;
    width: 40%;
    position: absolute;
    margin-top: 24px;
    max-width: 411px;
    background-size: 100%;
    min-width: 300px;
    background-position: bottom;
    margin-bottom: 10px;
}
nav   {
    top: 40px;
    position: absolute;
    right: 3%;
    width: auto;
    vertical-align: text-bottom;
    height: auto;
    padding: 0;
    font-size: 12px;
}
nav li {
    list-style: none;
    display: inline-block;
    vertical-align: bottom;
    height: auto;
    top: auto;
}
.menu-item   {
    text-decoration: none;
    list-style: none;
    font-family: "Courier";
    background-color: transparent;
    width: auto;
    display: inline-block;
    margin-right: 20px;
}
.menu-item a  , .menu-item a:visited, .menu-item a:active{
    color: #000;
    text-decoration: none;
    list-style: none;
}
.menu-item a:hover {
    color: #EC2726;
}
#searchform {
    font-family: "Courier";
    border: 1px solid #000000;
    margin-bottom: 1px;
    background-color: #fff;
}
#s {
    border: none;
    font-family: "Courier";
    margin-top: 0;
    margin-right: 0;
    margin-bottom: 0;
    background-color: transparent;
    margin-left: 5px;
}
#searchsubmit {
    border: none;
    font-family: "Courier";
    margin: 0;
    background-color: transparent;
}

#contentWrap {
    position: absolute;
    top: 100px;
    right: 0px;
    width: 100%;
    overflow: auto;
    bottom: 50px;
    margin-right: 0px;
    margin-top: 10px;
    margin-left: 0px;
}
.meta {
    width: 25%;
    position: relative;
    font-family: "Courier";
    font-size: 12px;
    margin-top: 20px;
    margin-right: 70%;
    margin-left: 0px;
    max-width: 200px;
    min-width: 100px;
}
.meta div {
    text-decoration: none;
    text-align: right;
    padding-right: 20px;
    padding-top: 0px;
}
.meta div a {
    text-decoration: none;
    color: #000;
}
.meta div a:hover, .meta div a:active {
    color: #EC2726;
}

.meta span {
    color: #EC2726;
    text-transform: lowercase;
}
#tags  {
    color: #000;
    margin-right: 10px;
    right: auto;
    width: auto;
}
.meta .pagination  {
    position: fixed;
    left: 2%;
    font-size: 14px;
    font-family: "Courier";
    bottom: 35px;
    text-decoration: none;
    max-width: 200px;
    vertical-align: middle;
    text-align: right;
    right: 70%;
    width: 23%;
}
.meta .pagination ul {
    padding-right: 25px;
}
.meta .pagination li {
    display: inline-block;
    list-style: none;
    text-decoration: none;
    font-family: "Courier";
    color: #000;
}
.meta .pagination a   , .meta .pagination a:visited{
    text-decoration: none;
    text-align: left;
    margin: 0;
    color: #000;
}
.meta .pagination a:hover , .meta .pagination a:active {
    color: #EC2726;
}
.meta2 {
    height: auto;
    width: 75%;
    margin-left: 21%;
    position: relative;
    padding-left: 15px;
    min-width: 300px;
    top: -50px;
}
.meta2 a            , .meta2 a:visited  {
    font-family: "Helvetica Neue";
    text-transform: lowercase;
    font-style: normal;
    font-weight: bolder;
    text-decoration: none;
    color: #000;
    font-size: 18px;
    margin-top: 10px;
}
a:hover,      a:active, .meta2 a:hover{
    color: #EC2726;
}
.entry p {
    font-family: Helvetica;
    font-size: 12px;
    font-style: normal;
    font-weight: 200;
    margin-bottom: 50px;
    margin-top: -15px;
}

footer {
    margin-top: 10px;
    position: fixed;
    bottom: 10px;
    width: 100%;
    height: 30px;
    /* [disabled]background-color: #f7f7f7; */
    border-top: 3px inset #636466;
    font-family: Courier;
    font-size: 10px;
    /* [disabled]display: inline; */
    left: 0px;
}
footer ul {
    float: right;
    margin-right: 3%;
    /* [disabled]margin-left: 5px; */
    display: inline-block;
    width: auto;
    list-style: none;
}

PS BTW道具用于将端点识别为单个单词,因此将其命名为getEndpoint,而不是getEndPoint。