为什么可以转换泛型类?

时间:2016-05-19 18:58:57

标签: java generics casting invariance

Java泛型是不变的,因此不可能进行这样的转换:

List<Object> li = (List<Object>)new ArrayList<Integer>();

但是在第4行的以下代码中,我可以从List<Integer>转换为List<T>,其中T可以是任何类型。为什么允许这种类型的演员?

我知道它会生成关于未经检查的强制转换的警告,但重点是在参数化方法中可以进行此强制转换,但在普通代码中则不行。请记住,泛型是不变的,为什么允许它?在使用List<Integer>的正常代码中,我只能将其强制转换为List<Integer>,这是没有意义的,其他强制转换是非法的。那么在第4行允许这样的演员有什么意义呢?

我知道泛型类型在编译时被删除,并以List xlist = (List)list结束,但在删除这些类型之前,显然不应该允许此强制转换,除非仅在有人通过Integer时才接受作为el没有多大意义。

class Test {

    public static <T> void t(List<Integer> list, T el) {
        List<T> xlist = (List<T>)list; //OK
        xlist.add(el);
    }

    public static void main(String[] args) {

        List<Integer> list = new ArrayList<>();
        t(list, "a");
        t(list, "b");

        //prints [a, b] even if List type is Integer
        System.out.println(list);

    }
}

3 个答案:

答案 0 :(得分:5)

在Java中,进行显式转换是一个编译错误,在编译时已知该转换始终不正确或始终正确。从List<Integer>List<Object>的强制转换在编译时始终是不正确的,因此不允许。从List<Integer>List<T>的强制转换在编译时并不知道总是不正确 - 如果TInteger并且T$i = 0; foreach($records as $r) { $html .= '<tr> <td>'.escape($r->tecnologia).'</td> <td>'.escape($r->normaespecificacion).'</td> <td><img src="functions/'.escape($r->foto).'"></td> <td>'.escape($r->marca).'</td> <td>'.escape($r->modelo).'</td> <td>'.escape($r->descripcion).'</td> <td>$'.escape($r->preciounitario).'</td> <td>$'.escape($r->iva).'</td> <td>$'.escape($r->instalacion).'</td> <td>$'.escape($r->totalcosto).'</td> <td>'.escape($r->garantia).'</td> <td><input type="text" value="0" class="imp" size="2" /></td> </tr>'; $i = $i+1; } ,那么这是正确的在编译时不知道。

答案 1 :(得分:1)

我想答案是这个演员表是可能的,因为Integer可以作为参数el传递,在这种情况下,演员表是正确的。在除Integer之外的所有其他类型的情况下,它将是非法的。但是正如我在泛型中看到的那样,如果至少有一种类型可以提供正确的强制转换(Integer),那么编译器不会给出错误,但警告,即使所有其他情况都无效。 / p>

答案 2 :(得分:0)

Object是Integer类的超类。 List<Object>不是类List<Integer>的超类,但是,如果您希望List<Object>引用List<Integer>,则可以使用百搭号(?)。 / p>

List<?> list1 = new List<Object>();
List<?> list2 = new List<Integer>();
list1 = list2;