考虑下面的方法doSomething(List) ,它接受List 作为参数。
1 2 3
private void doSomething( List< Object> list) {
// do something
}
现在考虑下面的代码片段,它试图调用doSomething() ,在这里我试图将List 传递给doSomething() 。
1 2 3 4 5
List< Object> objectList;
List< String> stringList;
doSomething( stringList) ; // compilation error incompatible types
doSomething( objectList) ; // works fine
甚至低于代码引发编译错误
1
objectList = stringList; // compilation error incompatible types
我的问题是,为什么不能将List 传递给接受List 的方法?
退房这个docs.oracle.com JavaSE教程:/ / / / / subtype.html泛型额外
List extends Object> 应该允许这样的工作
"abstractchaos真的,只要不涉及"做什么"List#add(...)
因为当String 扩展Object 时,List 不扩展List 。
更新:一般来说,如果Foo 是Bar 的子类型(子类或子接口),而G 是某种通用类型声明,则G 不是G 的子类型。
这是因为集合确实发生了变化。在您的情况下,如果List 是List 的子类型,那么当使用其父类型引用列表时,可以向其中添加除String 以外的类型,如下所示:
1 2 3 4
List
< String
> stringList
= new ArrayList
< String
>;
List
< Object
> objectList
= stringList
; // this does compile only if List<String> where subtypes of List<Object>
objectList.
add ( new Object ( ) ) ;
String s
= stringList.
get ( 0 ) ; // attempt to assign an Object to a String :O
Java编译器必须防止这些情况。
更多关于Java教程页面的详细说明。
简单准确。+ 1
+1;无论如何,您可以调用dosomething(((list)(list<?>)
虽然这个答案是真的,但看起来更像是对操作问题的确认。我觉得它缺少最重要的部分:"为什么List 不是List 的亚型?".
这个答案很简单,但看起来不完整。
@用户3374518,pshemo:我更新了我的答案,希望这能使它更好:)
如果成功,可以将类型错误的对象放入列表中:
1 2 3 4 5 6 7
private void doSomething
( List
< Object
> list
) {
list.
add ( new Integer ( 123 ) ) ; // Should be fine, it's an object
}
List
< String
> stringList
= new ArrayList
< String
> ( ) ;
doSomething
( stringList
) ; // If this worked....
String s
= stringList.
get ( 0 ) ; // ... you'd receive a ClassCastException here
+1,也许是这里最好的例子:)
P.S.:Angelikalanger.com/genericsfaq/faqsections/&hellip很好地解释了与泛型的超类型/子类型关系;
Java中的这个泛型问题可能会让任何一个对泛型不太熟悉的人感到困惑,因为乍看起来,它看起来像String是对象,所以EDCOX1(0)可以在需要EDCOX1×1的条件下使用,但这不是真的。它将导致编译错误。
如果你再往前走一步,这是有意义的,因为List 可以存储任何东西,包括String 、Integer 等,但是List 只能存储Strings 。
还要看一下:为什么不从列表继承?
选择作为答案,因为它使我更好地理解。
问题并不完全在于被调用方可以存储任何内容:真正的问题是,如果允许,调用方将无法确定是否有字符串实例,因此必须像在泛型之前的日子(instance of operator)那样处理它。
这些限制的原因与差异因素有关。
采用以下代码:
1 2 3 4
public void doSomething
( List
< Object
> objects
)
{
objects.
add ( new Object ( ) ) ;
}
展开示例,可以尝试执行以下操作:
1 2 3 4 5 6 7 8 9
List
< String
> strings
= new ArrayList
< String
> ( ) ;
string.
add ( "S1" ) ;
doSomething
( strings
) ;
for ( String s
: strings
)
{
System .
out .
println ( s.
length ) ;
}
希望很明显,如果编译器允许编译这段代码(而不是这样),那么这段代码会被破坏——当试图将Object 强制转换为String 时,列表中的第二项将出现ClassCastException 。
要能够传递通用集合类型,需要执行以下操作:
1 2 3 4 5 6 7
public void doSomething
( List
<?> objects
)
{
for ( Object obj
: objects
)
{
System .
out .
println ( obj.
toString ) ;
}
}
同样,编译器在监视你的背部,如果你用objects.add(new Object()) 替换System.out ,编译器将不允许这样做,因为objects 可能被创建为List 。
关于方差的更多背景,请参见维基百科的文章协方差和反方差。
由于Object 是String 的超类型,因此有时预期List 将是List 的超类型。
这种期望源于这样一个事实,即数组存在这样一种类型关系:
Object[] 是String[] 的超型,因为Object 是String 的超型。(这种类型的关系称为协方差。)
组件类型的超级子类型关系扩展到相应的数组类型中。
对于泛型类型的实例化,不存在此类类型关系。(参数化类型不是协变的。)
查看此处了解更多详细信息
来自泛型的Java教程:
让我们测试一下你对仿制药的理解。以下代码段合法吗?
1 2
List< String> ls = new ArrayList< String> ( ) ; // 1
List< Object> lo = ls; // 2
第一行当然是合法的。问题中比较棘手的部分是第2行。这可以归结为一个问题:字符串列表是对象列表。大多数人本能地回答:"当然!"
好吧,看看下面几行:
1 2
lo.
add ( new Object ( ) ) ; // 3
String s
= ls.
get ( 0 ) ; // 4: Attempts to assign an Object to a String!
这里我们有别名ls和lo。通过别名lo访问ls(字符串列表),我们可以在其中插入任意对象。结果,ls不再只持有字符串,当我们试图从中得到一些东西时,我们会得到一个粗鲁的惊喜。
Java编译器当然会阻止这种情况发生。第2行将导致编译时错误。
来源:泛型和子类型
如果您不确定它将采用什么样的数据类型,则可以使用Java中的泛型如下
1 2 3 4 5 6 7 8 9 10
public static void doSomething
( List
<?> data
) {
}
public static void main
( String [ ] args
) {
List
< Object
> objectList
= new ArrayList
< Object
> ( ) ;
List
< String
> stringList
= new ArrayList
< String
> ( ) ;
doSomething
( objectList
) ;
doSomething
( stringList
) ;
}
但是,在使用数据时,需要将适当的数据类型指定为类型转换
我想和这个问题没有关系
Ya,我知道与问题没有关系,但是既然你在这个问题上添加了适当的评论,认为使用Java中的泛型共享可能的通用方式是有益的: