2017-06-12 142 views
1

我想在T2的特定类型通过时将Object T投射到T2。 T2是一个来自接口T的类,所以可以有多个T2的实现。 就铸造而言,它正在发生。但是我无法访问类型化函数的功能。我做错了什么?如何从另一个泛型类参数中转换泛型参数?

protected <T, T2> SortedMap<Integer, T2> noNameFunction(List<T> things, T2 ts) { 
    SortedMap<Integer, Object> sortedMap = new TreeMap <> (); 
    for (T t: things) { 
     T2 as = ((T2) ts); 
     sortedMap.put (as.getSequence(), as.getFunctionsFromCastedIbjectA()); 
    } 
    return sortedMap; 
} 

我在概念上是否错了? 我该如何解决这个问题?

+0

你有没有试过使用'instaceof'? https://stackoverflow.com/questions/6601132/instanceof-keyword-usage – xsami

+0

你在哪里使用你的t变量?似乎从未使用过 –

+0

使用泛型时,您不应该施放任何东西。你是否通过泛型处理类型安全 –

回答

3

实际上,您无法从as调用编译器无法在编译时根据您对T2施加的约束条件来确定的任何方法。

在你的问题T2可以延长Object所以你只能调用其中的声明像toStringhashCode等方法......很没用任何东西。

如果出于任何原因可以缩小T2类型(因此T)来扩展一个更具体的类或接口,那么您会获取其部件的方法,例如设想T,因此T2,被保证是所以你可以拨打intValue

这可能会解决你的问题T方法,如getSequence我推测,其实T在你的代码为界,一些类定义getSequence方法。假设它叫SequenceContainer

protected <T extends SequenceContainer, T2 extends T> SortedMap<Integer, T2> noNameFunction(List<T> things, T2 ts) { 
    SortedMap<Integer, Object> sortedMap = new TreeMap <> (); 
    for (T t: things) { 
     T2 as = ((T2) t); 
     sortedMap.put (as.getSequence(), as.t2OwnMethod()); // fail to compile, due to the call to t2OwnMethod. 
    } 
    return sortedMap; 
} 

完整的解决方案是使用允许调用者提供需要在方法内调用的T2代码的lambda。我已经采取了这一机会,返回的有序映射的价值推广到第三类X

protected <T extends SequenceContainer, T2 extends T, X> SortedMap<Integer, X> noNameFunction(List<T> things, T2 ts, Function<T2, X> valueFunction) { 
    SortedMap<Integer, Object> sortedMap = new TreeMap <> (); 
    for (T t: things) { 
     T2 as = ((T2) t); 
     sortedMap.put (as.getSequence(), valueFunction.apply(as)); // fail to compile, due to the call to t2OwnMethod. 
    } 
    return sortedMap; 
} 

通知......这可能是简单地T2,将取决于你提供什么样的拉姆达在编译时无缝解决。现在的方式,你会调用这个签名假设t2OwnMethod回报......一个String说,就是:

List<? extends SequenceContainer> scs = ...; 
SpecialSequenceContainer exampleSSC = ...; /// SpecialSequenceContainer extends 
SortedMap<Integer, String> option1 = noNameFunction(scs, exampleSSC, ssc -> ssc.t2OwnMethod()); 
// or 
SortedMap<Integer, String> option2 = noNameFunction(scs, exampleSSC, 
    SpecialSequenceContainer::t2OwnMethod); 

现在,请注意第二个参数(exampleSSC)没什么用处...所以你可以简单地忽略它。

我们可以更进一步这里使用Java流做的所有工作中的问题代码:

final SortedMap<Integer, String> result = myScs.stream() 
    .map(t -> (SpecialSequenceContainer) t) 
    .collect(SequenceContainer::getSequence, 
       SpecialSequenceContainer::t2OwnMethod, 
       (s1, s2) -> s1, 
       TreeMap::new); 

注意,如果有键冲突(s1, s2) -> s1拉姆达只会被调用,也许永远不会是案例,但你需要提供价值合并功能,无论。

+2

我喜欢你的方法,upvoted!我只有几条意见...... 1)拥有泛型类型“T”似乎毫无意义。只需使用接口的类型,在你的情况下,这将是'SequenceContainer'。还让列表成为'List <? extends SequenceContainer>'2)除了提取值的函数之外,我还会使用一个函数来提取这些键,因此该方法将尽可能通用。流,没有必要的方法... –

+2

@ FedericoPeraltaSchaffner,是的'''列表<?扩展SequenceContainer>'''更加正确......可以说有一个机会,它可以进一步将真正的代码包含进另一个将T2定义为类型参数的方法中,这可以改写为'''List '''(并且地图或者演员阵容将会消失)......直到代码将知道T2实际是什么的级别。是的,你说得对'''T'''在这一点上是毫无意义的(没有平底球打算);还有一些东西可以从原始代码中改进,我刚刚指出了一些。 –