2012-10-14 148 views
7

我有一个容器(列表)的类型T的一些元素,并希望过滤它。因此它只包含特定子类型U的元素。是否可以设置“动态”返回类型?Java动态返回类型?

例如:

class SomeContainer<T> extends ArrayList<T>{ 

    public SomeContainer<T> subset(Class c){ 
     SomeContainer<...here the type of c > output = new SomeContainer<.. also ..>(); 

     //filter own elements and only add c-objects in the new list 

     return output; 
    } 
} 

目前,它返回普通类型T的列表,而不是c系列型(T的子类型)的。因为我想的一个亚型,并触发特定亚型的方法,我需要一个特定亚型列表对象后过滤列表

Note: SomeContainer.java uses unchecked or unsafe operations. 
Note: Recompile with -Xlint:unchecked for details. 

:所以我有时会收到以下编译器的通知。

+2

警告是因为您正在使用'Class'而不是'Class '。我不确定你可以在模板参数中使用动态类型。 – vainolo

+0

*因此它只包含特定子类型U的元素*为什么不用该特定子类型U声明? – m0skit0

回答

9

java.lang.Class是本身就是一个泛型类型参数,所以你可以使用它的类型参数,就像这样:

public <U extends T> SomeContainer<U> subset(Class<U> c){ 
    SomeContainer<U> output = new SomeContainer<U>(); 
    for (T val : this) { 
     if (c.isInstance(val)) { 
      output.add(c.cast(val)); 
     } 
    } 
    return output; 
} 
+3

或更好,'output.add(c.cast(val))'以避免未经检查的转换警告。 –

+0

@IanRoberts绝对!感谢您的一个伟大的建议! – dasblinkenlight

1

泛型只是编译时的人工制品,因此你的方案是行不通的。编译器无法预测每次执行调用此函数的代码行时您想要的类。除非你有一个非常有限而且很无用的情况,你只能使用类文字来调用你的函数,所以你不能使这个解决方案类型安全。但是,正如你所说,这几乎肯定会击败它的目的。

0

第一点:您可以删除未检查的操作警告,将Class c参数替换为Class<T> c。这可能是你所需要的......在这种情况下... = :-)

观点二: 通常调用SomeContainer.subset()的代码就知道在编译输入型U(从逻辑上下文) 。这必须是你的情况下,否则你将无法通过在Class c参数

尝试:

class SomeContainer<T> extends ArrayList<T>{ 

    public <U extends T> SomeContainer subset(Class<U> c){ 
     SomeContainer<U> output = new SomeContainer<U>(); 
     // put filtered elements into output 

     return output;  
    } 
} 

见我做什么呢?
在方法调用中引入第二个类型参数:​​。 也在Class<U> c的论点中使用了这个。
调用者将调用像(其中X是选择的T子类):

SomeContainer<X> mySubset = mySomeContainer.subset(X.class);  // type inference 
SomeContainer<X> mySubset = mySomeContainer.<X>subset(X.class); // type arg specified 


如果你需要的东西比这更动态,通配符可以帮助 - 允许的parametised“家庭”

public SomeContainer<? extends X> subset(Class<? extends X> c){ 

这是一个“塑料”功能界面:类型在&出传递你可以返回SomeContainer<T>SomeContainer<X>对于任何X是T的子类下面也适用:

public SomeContainer<? super Z> subset(Class<? extends X> c){ 

然而,作为另一的海报所说,泛型是编译时构建体,它们在替换产生的非通用代码编译。这意味着你不能动态地决定用一行代码实例化泛型的类型。但是你可以作一些小小的尝试:如果你的T的子类数量有限,比如说X,Y和Z,其中Z扩展Y,Y扩展Z,那么你可以使用一个很老的哈希“if语句”。尝试:

类SomeContainer扩展的ArrayList {

public SomeContainer<? extends X> subset(Class<? extends X> c){ 
    SomeContainer<? extends X> output = null; 

    // would like to use: "if (c instance of Class<Z>)" 
    // but instanceof does not allow generic type arguments 
    if (c.getName().equals(Z.class.getName())) { 
     SomeContainer<Z> outputZ = new SomeContainer<Z>(); 
     // put filtered elements into outputZ 
     output = outputZ; 
    } else if (c.getName().equals(Y.class.getName())) { 
     SomeContainer<Y> outputY = new SomeContainer<Y>(); 
     // put filtered elements into outputZ 
     output = outputY; 
    } else if (c.getName().equals(X.class.getName())) { 
     SomeContainer<X> outputX = new SomeContainer<X>(); 
     // put filtered elements into outputZ 
     output = outputX; 
    } 
    return output;  
} 

}

轻松! (或不)= :-)