为什么不能在列表中添加字符串?

时间:2010-01-29 08:25:39

标签: java generics

我们知道如果我们为列表声明泛型类型,我们可以在列表中添加字符串和整数。但代码似乎没有添加字符串。我无法理解的问题是什么..

class GHJ{String s;GHJ(String s){this.s=s;}}

class DFR{
    public static void main(String[] g){
        List<? extends Object> list=new ArrayList();
        list.add((new String("ffg")));// compiler error
        list.add("df");// compiler error
        list.add("sdd");// compiler error
        list.add(new GHJ("dff"));// compiler error
        String s= list.get(0);// compiler error
        System.out.println(list+" "+s);
    }   
}

11 个答案:

答案 0 :(得分:5)

正确的方法是使用泛型。

创建列表,如:

List<String> list = new ArrayList<String>();

然后你不需要施放。

<强>编辑:

正如dpb所指出的那样,有多种类型的对象。从我的角度来看,在列表中混合不同类型的对象会产生问题。解决问题的唯一方法是:

  • 不要使用泛型,一切都将成为列表中的对象
  • 当您需要检索某些内容时,需要执行以下操作:

    if (list.get(0) instanceof String) {
    } else if (list.get(0) instanceof GHJ) { 
    } ..... 
    

答案 1 :(得分:3)

在您的情况下,您无需将列表设为通用。只需使用

List list = new ArrayList();

这将创建Object类型的列表。

答案 2 :(得分:2)

您告诉编译器列表中的类型是扩展对象的类型。然后你将东西添加到列表中并尝试获取一个。所有的编译器都知道你得到的东西会扩展对象,而不是它肯定是一个字符串。您需要告诉编译器您从列表中获取了一个字符串。

如果你说

Object a= new String("blah");
String s;

你需要将一个字符串强制转换为s

s= (String) a;

如果你做了

,你的例子会发生什么
String s = list.get(3);

您放置了new GHJ("dff")

编译器如何知道每个位置的对象类型?

答案 3 :(得分:2)

只是为了补充卡洛斯的回答:

建议阅读Java语言指南 - &gt; http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html

并提供更全面的报道:

http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf

答案 4 :(得分:2)

你可以,但只能使用无类型(摆脱

<? super String> 

完全,所以:

List x = new List(); x.add(new Object()); x.add("blah!");

或通过为泛型参数

找到一个公共超类(在本例中,只是Object)
List<Object> x = new List<Object>(); x.add(new Object()); x.add("blah!");

你可以通过技巧将元素填充到列表中,绕过通用的类型检查,但这是非常糟糕的Juju。

答案 5 :(得分:2)

list的类型为List<? super String>,因此如果您想为其添加内容,则需要String或类似String的超类。唯一的String超类是ObjectGHJ不是String的超类,因此您无法将GHJ的实例添加到该列表中。

答案 6 :(得分:2)

如果你在列表中添加不同的类型,你必须告诉编译器你从列表中取出哪种类型,你无法绕过它。

您是否可以为每种类型的对象保留单独的列表,并且可能会保留包含各种类型列表的地图?然后你可以按类型获取每个列表,列表中的所有元素都是相同的类型?

答案 7 :(得分:1)

是的,您可以在列表中添加列表和对象,但唯一的方法是使用无类型列表。在这种情况下,您会丢失类型信息,并且必须手动将您从列表中取出的对象转换回其原始类型。

您可以使用instanceof来检查可以投射对象的类型,但这特别难看......

问题是:真的是否需要将字符串和对象放在同一个列表中?这对我来说就像一个代码味道。

答案 8 :(得分:0)

您需要从Object转换String,如下所示:

String s = (String)list.get(0);

答案 9 :(得分:0)

为什么会把字符串加起来? 它不能编译,因为需要强制转换:

String str = (String)list.get(0);

答案 10 :(得分:0)

外卡会把你弄得乱七八糟,因为它没有做你打算做的事情。当您需要引用一些通用泛型时,传统上使用通配符。

例如,如果您想让用户为您提供包含任何类型Object的集合,那么您的方法可以使用Collection<? extends Object>作为其参数。您可能希望这样做,因为如果您仅使用Collection<Object>作为参数,则他们无法传递Collection<String>

所以,问题是List<? extends Object>有一些限制因为编译器无法知道List采用什么特定类型。例如,它可能是List<String> ...编译器不知道。因此,您永远不能在List上调用任何以<? extends Object>作为参数的方法。换句话说,你不能调用add()。

你可以调用get()...因为编译器知道接收变量是什么类型,并且可以检查它是否正常。对象foo = myList.get(0)没问题。

我认为在这种情况下你真的想要List<Object>并确保在ArrayList上声明type参数。

List<Object> list = new ArrayList<Object>();

如果你想要字符串,那么你必须专门将对象转换为字符串。我个人建议使用String.valueOf()。

顺便说一句,上面的内容在Core Java第1卷的Generics章节的通配符部分很好地记录了(好吧,至少我的古老的JDK 1.5版本)。