试图了解泛型

时间:2012-02-23 11:53:34

标签: java generics arraylist

我有以下代码

public static void main(String[] args) {
        ArrayList<Integer> iList = new ArrayList();
        iList = returList();
        for (int i = 0; i < iList.size(); i++) {
            System.out.println(iList.get(i));
        }
    }

    public static ArrayList returList() {
        ArrayList al = new ArrayList();
        al.add("S");
        al.add(1);
        return al;
    }

现在我的查询是为什么Arraylist接受在'ArrayList iList = new ArrayList();'中创建原始arraylist对象的原因。甚至从方法调用返回甚至相同的情况。

现在,将会出现哪种类型的数据,泛型意味着什么?我看到没有编译错误,这个代码甚至运行良好。

6 个答案:

答案 0 :(得分:1)

泛型创建是为了帮助开发人员,但您必须使用它们才能获益。您的IDE将警告您对ArrayList的原始用法:

ArrayList is a raw type. References to generic type ArrayList<E> should be parameterized

但这并不妨碍你自己吊死,不。请注意,在某些IDE中,您实际上可以强制这些编译错误,这可能是您正在寻找的。

现在,就列表中的内容而言,它正是您放入其中的内容。请记住,泛型只是“语法糖”,编译器提示从生成的类中删除 完全 。因此,在运行时,没有指示对象具有什么泛型类型。在您的情况下,您的代码工作正常,因为您所做的只是打印出列表内容。您的所有对象都会自动转换为字符串!试试这个有趣的游戏:

public static void main(String[] args) {
        ArrayList<Integer> iList = new ArrayList();
        iList = returList();
        for (final Integer i: iList) {
            System.out.println(i.intValue());
        }
}

答案 1 :(得分:1)

阅读本文:http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf,建议使用两到三次。

答案 2 :(得分:1)

由于Java泛型的实现方式(请参阅Type Erasure以获得介绍性解释),可以创建泛型类的“原始”类型实例,然后将它们转换为通用版本,如同在{的赋值中一样{1}}。这会导致编译器警告,因为它可能是不安全的操作。您可以将任何类型的类型添加到原始ArrayList(它等同于ArrayList),但如果您将其转换为更具体的泛型类型,则可能会出现不一致的集合。

在您的示例中,您已在iList中创建了此类列表。但是,由于returList不依赖于传递给它的列表元素的类型,因此您的代码不会显示此内容。添加一行,例如

println()

到您的Integer val = iList.get(i); 循环并运行您的代码,当您的程序尝试将字符串for强制转换为ClassCastException时,您将获得"s"

当泛型集合不一致时,在尝试使用泛型类型访问不一致元素之前,您将无法找到。

答案 3 :(得分:0)

因为这是错的。这是正确完成的方式:

public static void main(String[] args) {
    List<Integer> iList = returList();
    for (int i = 0; i < iList.size(); i++) {
        System.out.println(iList.get(i));
    }
}

public static List<Integer> returList() {
    List<Integer> al = new ArrayList<Integer>();
    //al.add("S"); This line can't compile now!
    al.add(1);
    return al;
}

注意事项:

  1. 针对接口编程
  2. 避免不必要的初始化
  3. 在实现上使用类型参数(赋值运算符的RHS)

答案 4 :(得分:0)

已回答here

  

为什么允许原始类型?

     

原始类型   允许使用该语言主要是为了便于连接   使用非通用(遗留)代码。

     

例如,如果您有一个非通用的遗留方法,将List作为一个   参数,您可以将参数化类型(如List)传递给   那种方法。相反,如果你有一个返回List的方法,   您可以将结果分配给List类型的引用变量   如果您因某种原因知道返回的列表确实是一个   字符串列表。

答案 5 :(得分:0)

仿制药的一些历史可能有助于解释一些奇怪的事情。

当最初为Java提出泛型时,假设必须在不改变基础.class格式的情况下引入更改。因此,泛型被实现为原始类型的薄层。一种称为类型擦除的技术成为解决方案。这意味着编译器会删除所有泛型信息,以便在运行时不会获得通用信息。

这会产生令人讨厌的后果,您无法依赖源代码中显示的类型。

这就是你的例子中发生的事情。

有关详细信息,请参阅http://docs.oracle.com/javase/tutorial/java/generics/erasure.html

请注意,对于Java 5,最终更改了.class格式以适应自动装箱。由于时间限制,类格式正在改变,从而允许正确地完成泛型的事实没有被利用。