using methods from the interface where occurs contravariantly in the type of the method. Conversely, if had type one could call but not . While non-wildcard parameterized types in Java are invariant (e.g. there is no subtyping relationship between and ), wildcard types can be made more specific by specifying a tighter bound. For example, is a subtype of . This shows that wildcard types are covariant in their upper bounds (and also contravariant in their lower bounds). In total, given a wildcard type like , there are three ways to form a subtype: by specializing the class , by specifying a tighter bound , or by replacing the wildcard with a specific type (see figure). By applying two of the above three forms of subtyping, it becomes possible to, for example, pass an argument of type to a method expecting a . This is the kind of expressiveness that results from covariant interface types. The type acts as an interface type containing only the covariant methods of , but the implementer of did not have to define it ahead of time. In the common case of a generic data structure , covariant parameters are used for methods getting data out of the structure, and contravariant parameters for methods putting data into the structure. The mnemonic for Producer Extends, Consumer Super (PECS), from the book Effective Java by Joshua Bloch gives an easy way to remember when to use covariance and contravariance. Wildcards are flexible, but there is a drawback. While use-site variance means that API designers need not consider variance of type parameters to interfaces, they must often instead use more complicated method signatures. A common example involves the interface. Suppose we want to write a function that finds the biggest element in a collection. The elements need to implement the method, so a first try might be <T extends Comparable<T>> T max(Collection<T> coll); However, this type is not general enough—one can find the max of a , but not a . The problem is that does not implement , but instead the (better) interface . In Java, unlike in C#, is not considered a subtype of . Instead the type of has to be modified: <T extends Comparable<? super T>> T max(Collection<T> coll); The bounded wildcard conveys the information that calls only contravariant methods from the interface. This particular example is frustrating because all the methods in are