我们可以返回List <p>而不是List <! - ? - >?</p>

时间:2012-07-27 11:52:36

标签: java generics

为什么以下代码不会引发异常?

import java.util.ArrayList;
import java.util.List;

@SuppressWarnings("unchecked")
public class MainRunner {
    public static void main(String[] args) {
    List<String> s = new ArrayList<String>() {
        {
        add("a");
        add("1");
        add("1");
        }
    };
    // List<Integer> i = (List<Integer>) listConvertor(s, new Integer("1"));
    List<Integer> i = (List<Integer>) listConvertor(s, Integer.class);
    System.out.println(i);
    }

    @SuppressWarnings("unchecked")
    public static <T, P> List<?> listConvertor(List<T> inputList, P outputClass) {
    List<P> outputList = new ArrayList<P>(inputList.size());
    for (T t : inputList) {
        outputList.add((P) t); // shouldn't be classCastException here?
    }

    return outputList;

    }

}

我想返回List<P>而不是List<?>。但是当我写List<P>时,它意味着List<Class<P>>。即在上述情况下,它表示List<Class<Integer>>,但我希望List<Integer>作为回报。

我想要下面的代码:(这样我不必在方法返回时再次强制转换)

List<Integer> i =   listConvertor(s, Integer.class);
        System.out.println(i);
        }

        @SuppressWarnings("unchecked")
        public static <T, P> List<P> listConvertor(List<T> inputList, P outputClass) {
        List<P> outputList = new ArrayList<P>(inputList.size());
        for (T t : inputList) {
            outputList.add((P) t); // shouldn't be classCastException here?
        }

        return outputList;

        }

    }

4 个答案:

答案 0 :(得分:1)

public static <T, P> List<P> listConvertor(List<T> inputList, Class<P> outputClass) {

记住,您传递的是Class对象,而不是整数对象。

答案 1 :(得分:1)

不,当然它不会引发异常。泛型用于编译时检查,而不是运行时。在运行时,所有列表都是List<Object>,并且由JVM隐式地进行转换。


修改:在您的代码中

for (T t : inputList) {
  outputList.add((P) t); // shouldn't be classCastException here?
}

实际编译为

for (Object t : inputList) {
  outputList.add((Object) t); // shouldn't be classCastException here? -- no
}

例如,使用您的代码,如果您执行i.get(0).getClass(),则然后会获得ClassCastException,因为该项目无法从String转换为{{} 1}}(注意:同样适用于您,因为您无法隐式地将Integer.class投射到String。期间。)

如果您真的想要这样做,请将Integer强制转换为T(例如,将字符串转换为数字值),然后我建议您使用其他模式。例如:

P

您需要做的就是将static interface ClassConverter<F,T> { public T convert(F o); } static class StringToIntConverter implements ClassConverter<String,Integer> { public Integer convert(String o) { try { return Integer.parseInt(o); } catch (NumberFormatException e) { return 0; } } } public static void main(String[] args) { List<String> s = new ArrayList<String>() { { add("a"); add("1"); add("1"); } }; // List<Integer> i = (List<Integer>) listConvertor(s, new Integer("1")); List<Integer> i = (List<Integer>) listConvertor(s, new StringToIntConverter()); System.out.println(i); System.out.println(i.get(0).getClass().getName()); } public static <T, P> List<P> listConvertor(List<T> inputList, ClassConverter<T, P> c) { List<P> outputList = new ArrayList<P>(inputList.size()); for (T t : inputList) { outputList.add(c.convert(t)); // cast handled by the class method == safer } return outputList; } 接口实现为您希望将ClassConverter转换为T并将其传递给P方法的任何类型。

答案 2 :(得分:1)

这应该可以轻而易举地完成工作:

public static <T, P> List<P> listConvertor(List<T> inputList, Class<P> outputClass) {
    List<P> outputList = new ArrayList<P>(inputList.size());
    for (T t : inputList) {
        if( !outputClass.isInstance(t) )
            throw new ClassCastException("Faked CCException");
        @SuppressWarnings("unchecked")
        P p = (P) t;
        outputList.add(p);
    }

    return outputList;
}
  • 在来电方面没有演员
  • 如果源列表中包含不合适的类型,则
  • 例外。

答案 3 :(得分:0)

与@ A.H.的答案相同,但使用Class.cast()进行了大量简化,并且还摆脱了不必要的T

public static <P> List<P> listConvertor(List<?> inputList, Class<P> outputClass) {
    List<P> outputList = new ArrayList<P>(inputList.size());
    for (Object t : inputList) {
        P p = outputClass.cast(t);
        outputList.add(p);
    }

    return outputList;
}