1 2 3 4 5 6 7
public static void main( String [ ] args) {
List<? extends Object> mylist = new ArrayList< Object> ( ) ;
mylist.add ( "Java" ) ; // compile error
}
上面的代码不允许您将元素添加到列表中,通配符只能用作方法中的签名,同样不能用于添加,而只能用于访问。
在这种情况下,以上目的是什么?
假设您有一个接口和两个类:
1 2 3
interface IResult { }
class AResult implements IResult { }
class BResult implements IResult { }
然后,您将得到返回结果列表的类:
1 2 3 4 5 6 7 8 9 10 11 12 13
interface ITest< T extends IResult> {
List< T > getResult( ) ;
}
class ATest implements ITest< AResult> {
// look, overridden!
List< AResult> getResult( ) ;
}
class BTest implements ITest< BResult> {
// overridden again!
List< BResult> getResult( ) ;
}
当您需要"协变量返回",但是您返回集合而不是自己的对象时,这是一个很好的解决方案。最大的好处是,当独立于ITest接口使用ATest和BTest时,不必强制转换对象。但是,使用ITest接口时,不能将任何东西添加到返回的列表中-无法确定列表真正包含的对象类型!如果允许,则可以将BResult添加到List (作为List <?扩展T>返回),这没有任何意义。
因此,您必须记住以下内容:List <? X>扩展定义了一个可以轻松覆盖的列表,但它是只读的。
约书亚·布洛赫(Joshua Bloch)在他的著作《有效的Java》(第二版)中解释了他所谓的使用泛型的生产者/消费者原则。 Josh的解释应该告诉您为什么您的示例不起作用(编译)...
第5章(泛型)可在此处免费获得:http://java.sun.com/docs/books/effective/generics.pdf
有关此书(和作者)的更多信息,请访问:http://java.sun.com/docs/books/effective/
有界通配符类型的要点是它们在方法签名中的使用,以增加API的灵活性。例如,如果实现了通用Stack ,则可以提供一种将多个元素压入堆栈的方法,如下所示:
1 2 3 4 5
public void pushAll( Iterable<? extends E> elements) {
for ( E element : elements) {
push( e) ;
}
}
与没有通配符的pushAll(Iterable elements) 签名相比,它的优点在于它允许将E 的子类型的集合传递给方法-通常不被允许,因为Iterable 在某种程度上与直觉相反,不是Iterable 的子类。
对于使用通配符的Java泛型,假设只打算从通配符中读取,则可以使用上述声明。
不允许对其进行添加/写入,因为必须在编译时剥离所有泛型类型,并且在编译时,编译器没有办法知道List只是字符串,(它可以是任何对象,包括字符串! )
但是,您可以从中读取内容,因为它们将至少是对象。在Java集合中不允许混合使用不同的类型以保持内容的清洁和可理解,这有助于确保这一点。
Java泛型:集合中的通配符
延伸
超
?
今天,我将向您解释通配符的作用。理解这个概念有点困难
现在,假设您有一个抽象类,并且您有一个名为paintObject()的抽象方法。
1
Now you want to use different type of collection in every child class .
这是AbstractMain方法。
在这里,我们针对此Abstract Main方法采取的步骤
1.我们创建了抽象类
2.在参数中,我们定义了T(您可以使用任何字符)
-在这种情况下,无论哪个类实现了此方法,它都可以使用任何类型的类。
例如类可以实现类似的方法
public void paintObject(ArrayList对象)或public void paintObject(HashSet对象)
3.并且我们还使用了E扩展MainColorTO
-在这种情况下E扩展MainColorTo
-显然这意味着您要使用的任何类都必须是MainColorTo的子类
4.我们定义了一个抽象方法,称为paintObject(T object,E objectTO)
-现在无论哪种类都是实现方法,该方法都可以在该方法必须使用MainColorTO类型的第一个参数和第二个参数上使用任何类
1 2 3
public abstract class AbstractMain< T,E extends MainColorTO> {
public abstract void paintObject( T Object ,E TO) ;
}
现在我们将扩展到抽象类之上,并在其下实现方法
例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
public class MainColorTO {
public void paintColor( ) {
System .out .println ( "Paint Color........" ) ;
}
}
public class RedTO extends MainColorTO {
@Override
public void paintColor( ) {
System .out .println ( "RedTO......" ) ;
}
}
public class WhiteTO extends MainColorTO {
@Override
public void paintColor( ) {
System .out .println ( "White TO......" ) ;
}
}
现在我们举两个例子。
1.PaintHome.java
1 2 3 4 5 6 7
public class PaintHome extends AbstractMain< ArrayList , RedTO> {
@Override
public void paintObject( ArrayList arrayList,RedTO red) {
System .out .println ( arrayList) ;
}
}
现在在上面的PaintHome.java中,您可以检查我们是否在第一个参数中使用了ArrayList(因为可以使用任何类),在第二个参数中我们使用了RedTO(正在扩展MainColorTO)
2,PaintCar.java
1 2 3 4 5 6 7
public class PaintCar extends AbstractMain< HashSet , WhiteTO> {
@Override
public void paintObject( HashSet Object ,WhiteTO white) {
System .out .println ( Object ) ;
}
}
现在在上面的PaintCar.java中,您可以检查我们是否在第一个参数中使用了HashSet(因为我们可以使用任何类),在第二个参数中我们使用了WhiteTO(正在扩展MainColorTO)
要记住的Ponint
您不能在课程级别使用super关键字,而只能在课程级别使用extends关键字
1 2 3 4 5
public abstract class AbstractMain< P,E super MainColorTO> {
public abstract void paintObject( P Object ,E TO) ;
}
上面的代码将给您编译器错误。
与List< ? > 相同的List<? extends Object> 满足了归纳所有类型List ,List ,List 等的目的(因此,所有具有正确类型的类型都可以代替? ) 。所有这些类型的值都可以分配给类型List< ? > 的变量(这与List 有所不同!)。
通常,您不能将字符串添加到此类列表。但是,您可以从列表中读取Object ,也可以添加null 。您还可以计算列表的长度,等等。这些是可以保证对每种类型都适用的操作。
有关通配符的良好介绍,请参见论文"将通配符添加到Java编程语言"。这是一篇学术论文,但仍然很容易阅读。
这有效:
1 2
List<? super Object> mylist = new ArrayList< Object> ( ) ;
mylist.add ( "Java" ) ; // no compile error
从O'Reilly的Java泛型:
The Get and Put Principle: use an extends wildcard when you only get values our of a structure, use a super wildcard when you only put values into a structure, and don't use a wildcard you both get and put.