Angelika Langer - Training & Consulting

 
HOME | SEMINARS | TALKS | ARTICLES | BOOKS | LINKS | IOSTREAMS | GENERICS | ABOUT | NEWSLETTER | CONTACT | SITEMAP
Java Generics FAQs - Programming With Java Generics

Books  
HOME 
SEMINARS 
TALKS 
ARTICLES 
BOOKS 
LINKS 
IOSTREAMS 

GENERICS
  FAQ    
    CONTENT
    FUNDAMENTALS
    FEATURES
    PRACTICAL
    TECHNICAL
    INFORMATION
    GLOSSARY
    INDEX
    PDF VERSION
 
ABOUT 
NEWSLETTER 
CONTACT 
SITEMAP 
This is a collection of answers to frequently asked questions (FAQs) about Java Generics, a new language feature added to the Java programming language in version 5.0 of the Java Standard Edition (J2SE 5.0).

If you want to provide feedback or have any questions regarding Java generics, to which you cannot find an answer in this document, feel free to send me EMAIL or use the GENERICS FAQ form.
A printable version of the FAQ documents is available in PDF format (2.5MB).


 

Java Generics FAQs - Programming With Java Generics

Practicalities - Programming With Java Generics

© Copyright 2004-2007 by Angelika Langer.  All Rights Reserved.
Using Generic Types Using Generic Methods Coping With Legacy Defining Generic Types and Methods Designing Generic Methods Working With Generic Interfaces Implementing Infrastructure Methods Using Runtime Type Information Reflection

Programming With Generics


 

Using Generic Types and Methods

Should I prefer parameterized types over raw types?

Yes, using parameterized types has various advantages and is recommended, unless you have  a compelling reason to prefer the raw type.
It is permitted to use generic types without type arguments, that is, in their raw form. In principle, you can entirely ignore Java Generics and use raw types throughout your programs.  It is, however, recommended that type arguments are provided when a generic type is used, unless there is a compelling reason not to do so. 

Providing the type arguments rather than using the raw type has a couple of advantages: 

  • Improved readability.   An instantiation with type arguments is more informative and improves the readability of the source code.
  • Better tool support. Providing type arguments enables development tools to support you more effectively: IDEs (= integrated develepment environments) can offer more precise context-sensitive information; incremental compilers can flag type errors the moment you type in the incorrect source code.  Without providing type arguments the errors would  go undetected until you start testing your program. 
  • Fewer ClassCastExceptions.     Type arguments enable the compiler to perform static type checks to ensure type safety at compile time, as opposed to dynamic type checks performed by the virtual machine at runtime.  As a result there are fewer opportunities for the program to raise a ClassCastException .
  • Fewer casts. More specific type informations is available when type arguments are provided, so that hardly any casts are needed compared to the substantial number of casts that clutter the source code when raw types are used.
  • No unchecked warnings.  Raw types lead to "unchecked" warning, which can be prevented by use of type arguments.
  • No future deprecation. The Java Language Specification states that raw types might be deprecated in a future version of Java, and might ultimately be withdrawn as a language feature.
Raw types have an advantage, too: 
  • Zero learning effort. If you ignore Java Generics and use raw types everywhere in you program you need not familiarize yourself with new language features or learn how to read any puzzling error messages.
Advantages that are no advantages: 
  • Improved Performance .  Especially C++ programmers might expect that generic programs are more efficient than non-generic programs, because C++ templates can boost runtime efficiency.  However, if you take a look under the hood of the Java compiler and study how the compiler translates generic source code to byte code you realize that Java code using parameterized types does not perform any faster than non-generic programs. 
LINK TO THIS #FAQ001
REFERENCES How does the compiler translate Java generics?
What is an "unchecked" warning?
What is the benefit of using Java generics?

Why shouldn't I mix parameterized and raw types, if I feel like it?
 
Because it is poor style and highly confusing to readers of your source code.
Despite of the benefits of parameterized types you might still prefer use of raw types over using pre-defined generic types in their parameterized form, perhaps because the raw types look more familiar. To some extent it is a matter of style and taste and both styles are permitted.  No matter what your preferences are: be consistent and stick to it.  Either ignore Java generics and use raw type in all places, or take advantage of the improved type-safety and provide type arguments in all places. Mixing both styles is confusing and results in "unchecked" warnings that can and should be avoided. 

Naturally, you have to mix both styles when you interface with source code that was written before the advent of Java generics. In these cases you cannot avoid the mix and the inevitable "unchecked" warnings. However, one should never have any "unchecked" warnings in code that is written in generic style and does not interface with non-generic APIs. 

Here is a typical beginner's mistake for illustration. 

Example (of poor programming style): 

List <String> list = new ArrayList <String> ();
Iterator iter = list.iterator(); 
String s = (String) iter.next();
...
Beginners often start out correctly providing type arguments and suddenly forget, in the heat of the fighting, that methods of parameterized types often return other parameterized types.  This way they end up with a mix of generic and non-generic programming style, where there is no need for it.  Avoid mistakes like this and provide type arguments in all places. 

Example (corrected): 

List <String> list = new ArrayList <String> ();
Iterator <String> iter = list.iterator(); 
String s = iter.next();
...
Here is an example of a code snippet that produces avoidable "unchecked" warnings. 

Example (of avoidable "unchecked" warning): 

void f(Object obj) {
  Class type = obj.getClass();
  Annotation a = type.getAnnotation(Documented.class); // unchecked warning
  ...
}


warning: [unchecked] unchecked call to <A>getAnnotation(java.lang.Class<A>) as a member of the raw type java.lang.Class
        Annotation a = type.getAnnotation(Documented.class);
                                         ^
The getClass method returns an instantiation of class Class , namely Class<? extends X> , where X is the erasure of the static type of the expression on which getClass is called. In the example, the parameterization of the return type is ignored and the raw type Class is used instead.  As a result, certain method calls, such as the invocation of getAnnotation , are flagged with an "unchecked" warning. 

In general, it is recommended that type arguments are provided unless there is a compelling reason not to do so.  In case of doubt, often the unbounded wildcard parameterized type is the best alternative to the raw type.  It is sematically equivalent, eliminates "unchecked" warnings and yields to error messages if their use is unsafe. 

Example (corrected): 

void f(Object obj) {
  Class <?> type = obj.getClass();
  Annotation a = type.getAnnotation(Documented.class); 
  ...
}
LINK TO THIS #FAQ002
REFERENCES What is the benefit of using Java generics?
What does type-safety mean?
What is an "unchecked" warning?
What is the raw type?
What is a parameterized or generic)type?
How is a generic type instantiated?
What is an unbounded wildcard parameterized type?

Should I use the generic collections or stick to the old non-generic collections?
 
Provide type arguments when you use collections; it improves clarity and expressiveness of your source code.
The JDK collection framework has been re-engineered. All collections are generic types since Java 5.0.  In principle, you can choose whether you want to use the pre-defined generic collections in their parameterized or raw form.  Both is permitted, but use of the parameterized form is recommended because it improves the readability of your source code. 

Let us compare the generic and non-generic programming style and see how they differ. 

Example (of non-generic style): 

    final class HtmlProcessor {
        public static Collection process( Collection files) {
            Collection imageFileNames = new TreeSet();
            for (Iterator i = files.iterator(); i.hasNext(); ) {
                URI uri = (URI) i.next();
                Collection tokens = HtmlTokenizer.tokenize(new File(uri));
                imageFileNames.addAll(ImageCollector.collect(tokens));  // unchecked warning
            }
            return imageFileNames;
        }
    }
    final class ImageCollector {
        public static Collection collect( Collection tokens) {
            Set images = new TreeSet();
            for (Iterator i = tokens.iterator(); i.hasNext(); ) {
                HtmlToken tok = (HtmlToken) i.next();
                if (tok.getTag().3("img") && tok.hasAttribute("src"))  {
                    Attribute attr = tok.getAttribute("src");
                    images.add(attr.getValue());       // unchecked warning
                } 
            }
            return images;
        }
    }

From the code snippet above it is relatively difficult to tell what the various collections contain.  This is typical for non-generic code.  The raw type collections do not carry information regarding their elements.  This lack of type information also requires that we cast to the alledged element type each time an element is retrieved from any of the collections.  Each of these casts can potentially fail at runtime with a ClassCastException . ClassCastException s are a phenomenon typical to non-generic code. 

If we translate this non-generic source code with a Java 5.0 compiler, we  receive "unchecked" warnings when we invoke certain operations on the raw type collections.  We would certainly ignore all these warnings, or suppress them with the SuppressWarnings annotation. 

Example (of generic counterpart): 

    final class HtmlProcessor {
        public static Collection<String> process( Collection<URI> files) {
            Collection<String> imageFileNames = new TreeSet<String>();
            for (URI uri : files) {
                Collection<HtmlToken> tokens = HtmlTokenizer.tokenize(new File(uri));
                imageFileNames.addAll(ImageCollector.collect(tokens));
            }
            return imageFileNames;
        }
    }
    final class ImageCollector { 
        public static Collection<String> collect( Collection<HtmlToken> tokens) {
            Set<String> images = new TreeSet<String>();
            for (HtmlToken tok : tokens) {
                if (tok.getTag().equals("img") && tok.hasAttribute("src"))  {
                    Attribute attr = tok.getAttribute("src");
                    images.add(attr.getValue());
                } 
            }
            return images;
        }
    }

From the generic source code we can easily tell what type of elements are stored in the various collections. This is one of the benefits of generic Java: the source code is substantially more expressive and captures more of the programmer's intent. In addition it enables the compiler to perform lots of type checks at compile time that would otherwise be performed at runtime.  Note that we got rid of all casts. As a consequence there will be no runtime failure due to a ClassCastException

This is a general rule in Java 5.0:  if your source code compiled without any warnings then there will be no unexpected ClassCastException s at runtime. Of course, if your code contains explicit cast expressions any exceptions resulting from these casts are not considered unexpected.  But the number of casts in your source code will drop substantially with the use of generics. 
 

LINK TO THIS #FAQ003
REFERENCES package java.util
Should I prefer parameterized types over raw types?
What is the benefit of using Java generics?
What is an "unchecked" warning?
How can I disable or enable unchecked warnings?
What is the SuppressWarnings annotation?
What is the raw type?
What is a parameterized or generic type?
How is a generic type instantiated?

What is a checked collection?
 
A view to a regular collection that performs a runtime type check each time an element is inserted.
Despite of all the type checks that the compiler performs based on type arguments in order to ensure type safety it is still possible to smuggle elements of the wrong type into a generic collection.  This can happen easily when generic and non-generic code is mixed. 

Example (of smuggling an alien into a collection): 

class Legacy {
  public static List create() {
    List rawList = new ArrayList();
    rawList.add("abc");            // unchecked warning
    ...
    return rawList;
  }
  public static void insert(List rawList) {
    ... 
    rawList.add(new Date ());        // unchecked warning
    ...
  }
}
class Modern {
  private void someMethod() {
    List< String > stringList = Legacy.create();  // unchecked warning
    Legacy.insert(stringList); 
    Unrelated.useStringList(stringList);
  }
}
class Unrelated {
  public static void useStringList(List<String> stringList) {
    ...
    String s = stringList.get(1);   // ClassCastException
    ...
  }
}
An "alien" Date object is successfully inserted into a list of strings.  This can happen inadvertantly when a parameterized type is passed to a piece of legacy code that accepts the corresponding raw type and then adds alien elements.  The compiler can neither detect nor prevent this kind of violation of the type safety, beyond issuing an "unchecked" warning when certain methods of the raw type are invoked. The inevitable type mismatch will later show up in a potentially unrelated part of the program and will mainfest itself as an unexpected ClassCastException

For purposes of diagnostics and debugging JDK 5.0 adds a set of &ldquo;checked&rdquo; views to the collection framework (see java.util.Collections ), which can detect the kind of problem explained above.  If a checked view is used instead of the original collection then the error is reported at the correct location, namely when the "alien" element is inserted. 

Example (of using a checked collection): 

class Legacy {
  public static List create() {
    List rawList = new ArrayList();
    rawList.add("abc");          // unchecked warning
    ...
    return rawList;
  }
  public static void insert(List rawList) {
    ... 
    rawList.add(new Date());     // ClassCastException
    ...
  }
}
class Modern {
  private void someMethod() {
    List<String> stringList 
      = Collections.checkedList (L egacy.create() ,String.class) ; // unchecked warning
    Legacy.insert(stringList); 
    Unrelated.useStringList(stringList);
  }
}
class Unrelated
  public static void useStringList(List<String> stringList) {
    ...
    String s = stringList.get(1); 
    ...
  }
}
The checked collection is a view to an underlying collection, similar to the unmodifiable and synchronized views provided by class Collections . The purpose of the checked view is to detect insertion of "aliens" and prevent it by throwing a ClassCastException in case the element to be inserted is of an unexptected type.  The expected type of the elements is provided by means of a Class object when the checked view is created. Each time an element is added to the checked collection a runtime type check is performed to make sure that element is of an acceptable type.  Here is a snippet of the implementation of  the checked view for illustration. 

Example (excerpt from a checked view implementation): 

public class Collections { 
  public static <E> Collection<E> checkedCollection(Collection<E> c, Class<E> type ) {
    return new CheckedCollection<E>(c, type);
  }
  private static class CheckedCollection<E> implements Collection<E> {
    final Collection<E> c;
    final Class<E> type;

    CheckedCollection(Collection<E> c, Class<E> type) {
      this.c = c;
      this.type = type;
    }
    public boolean add(E o){
      if (! type.isInstance (o))
        throw new ClassCastException();
      return c.add(o);
    }
  }
}

The advantage of using a checked view is that the error is reported at the correct location. The downside of using a checked collection is the performance overhead of an additional dynamic type check each time an element is inserted into the collection. 

The error detection capabilities of the checked view are somewhat limited.  The type check that is performed when an element is inserted into a checked collection is performed at runtime - using the runtime type representation of the expected element type.  If the element type is a parameterized type the check cannot be exact, because only the raw type is available at runtime.  As a result, aliens can be inserted into a checked collection, although the checked collection was invented to prevent exactly that. 

Example (of limitations of checked collections): 

class Legacy {
  public static List legacyCreate() {
    List rawList = new ArrayList();
    rawList.add(new Pair("abc","xyz"));  // unchecked warning
    ...
    return rawList;
  }
  public static void legacyInsert(List rawList) {
    ... 
    rawList.add(new Pair(new Date(),"Xmas") );        // unchecked warning
    ...
  }
}
class Modern {
  private void someModernMethod() {
    List< Pair<String,String> > stringPairs 
      = Collections.checkedList( legacyCreate() ,Pair.class) ; // unchecked warning
    Legacy.insert(stringPairs); 
    Unrelated.useStringPairs(stringPairs);
  }
}
class Unrelated {
  public static void useStringPairs(List<Pair<String,String>> stringPairList) {
    ...
    String s = stringPairList.get(1).getFirst(); // ClassCastException
    ...
  }
}
The checked view can only check against the raw type Pair and cannot prevent that an alien pair of type Pair<Date,String> is inserted into the checked view to a collection of Pair<String,String> .  Remember, parameterized types do not have an exact runtime type representation and there is not class literal for a parameterized type that we could provide for creation of the checked view. 

Note, that a checked view to a collection of type Pair<String,String> cannot be created without a warning. 

Example: 

Lis t<Pair<String,String>> stringPairs 
      = Collections.checkedList
        (new ArrayList< Pair<String,String> > () , Pair .class); // error

Lis t<Pair<String,String>> stringPairs 
      = Collections.checkedList
        ( (List<Pair>) (new ArrayList< Pair<String,String> > ()) , Pair .class); // error

Lis t<Pair<String,String>> stringPairs 
      = Collections.checkedList
        ( (List) (new ArrayList< Pair<String,String> > ()) , Pair .class); // unchecked warning

We cannot create a checked view to a parameterized type such as List<Pair<String,String>> , because it is required that we supply the runtime type representation of the collection's element type as the second argument to the factory method Collections.checkedList .  The element type Pair<String,String> does not have a runtime type representation of its own; there is no such thing as Pair<String,String>.class .  At best, we can specify the raw type Pair as the runtime type representation of the collection's element type.  But this is the element type of a collection of type List<Pair> , not of a List<Pair<String,String>>

This explains why we have to add a cast.  The natural cast would be to type List<Pair> , but the conversion from ArrayList<Pair<String,String>> to List<Pair> is not permitted. These two types a inconvertible because they are instantiations of the same generic type for different type arguments. 

As a workaround we resort to the raw type List , because the conversion ArrayList<Pair<String,String>> to List is permitted for reasons of compatibility.  Use of the raw type results in the usual "unchecked" warnings.  In this case the compiler complains that we pass a raw type List as the first arguments to the Collections.checkedList method, where actually a List<Pair> is exptected. 

In general, we cannot create a checked view  to an instantiation of a collection whose type argument is a parameterized type (such as List<Pair<String,String>> ). This is only possible using debatable casts, as demonstrated above.  However, it is likely that checked collections are used in cases where generic and non-generic legacy code is mixed, because that is the situation in which alien elements can be inserted into a collection inadvertantly.  In a mixed style context, you might not even notice that you work around some of the compiler's type checks, when you create a checked view, because you have to cope with countless "unchecked" warnings anyway. 

The point to take home is that checked views provide a certain safety net for collections whose element type is a raw type, but fails to provide the same kind of safety for collections whose element type is a parameterized type.

LINK TO THIS #FAQ004
REFERENCES class java.util.Collections
What is an "unchecked" warning?
What is the raw type?
What happens when I mix generic and non-generic code?
How do I pass type information to a method so that it can be used at runtime?
How do I perform a runtime type check whose target type is a type parameter?
Why is there no class literal for concrete parameterized types?
How does the compiler translate Java generics?
What is type erasure?
What is the type erasure of a parameterized type? 

What is the difference between a Collection<?> and a Collection<Object>?

Collection<Object> is a heterogenous collection, while Collection<?> is a homogenous collection of elements of the same unknown type.
The type Collection<Object> is a heterogenous collection of objects of different types.  It's a mixed bag and can contain elements of all reference types. 

The type Collection<?> stands for a representative from the family of types that are instantiations of the generic interface Collection , where the type argument is an arbitrary reference type.  For instance, it refers to a Collection<Date> , or a Collection<String> , or a Collection<Number> , or even a Collection<Object>

A Collection<?> is a homogenous collection in the sense that it can only contain elements that have a common unknown supertype, and that unknown supertype might be more restrictive than Object .  If the unknown supertype is a final class then the collection is truly homogenous.  Otherwise, the collection is not really homogenous because it can contain objects of different types, but all these types are subtypes of the unknown supertype. For instance, the Collection<?> might stand for Collection<Number> , which is homogenous in the sense that it contains numbers and not apples or pears, yet it can contain a mix of elements of type Short , Integer , Long , etc. 
 

A similar distinction applies to bounded wildcards, not just the unbounded wildcard " ? ". 

A List<Iterable> is a concrete parameterized type.  It is a mixed list of objects whose type is a subtype of Iterable .  I can contain an ArrayList and a TreeSet and a SynchronousQueue , and so on. 

A List<? extends Iterable> is a wildcard parameterized type and stands for a representative from the family of types that are instantiations of the generic interface List , where the type argument is a subtype of Iterable , or Iterable itself.  Again, the list is truly homogenous if the unknown subtype of Iterable is a final class.  Otherwise, it is a mix of objects with a common unknown supertype and that supertype itself is a subtype of Iterable .  For example, List<? extends Iterable> might stand for List<Set> , which is homogenous in the sense that it contains sets and not lists or queues. Yet the List<Set> can be heterogenous because it might contain a mix of TreeSet s and HashSet s.

LINK TO THIS #FAQ005
REFERENCES What is a concrete parameterized type?
What is a wildcard parameterized type?

How do I express that a collection is a mix of objects of different types?

Using wildcard instantiations of the generic collections.
Occasionally, we want to refer to sequences of objects of different types. An example would be a List<Object> or a Object[] . Both denote sequences of objects of arbitrary types, because Object is the supertype of all reference types.

How do we express a sequence of objects not of arbitrary different types, but of different instantiations of a certain generic type? Say, we need to refer to a sequence of pairs of arbitrary elements. We would need the supertype of all instantiations of the generic Pair type. This supertype is the unbounded wildcard instantiation Pair<?,?> . Hence a List<Pair<?,?>> and a Pair<?,?>[] would denote sequences of pairs of different types.
 
of any type of any pair type
collection List<Object> List<Pair<?,?>>
array Object[] Pair<?,?>[]

When we want to refer to a mixed sequence of certain types, instead of all arbitrary types, we use the supertype of those "certain types" to express the mixed sequence. Examples are List<Number> or Number[]. The corresponding mixed sequences of instantiations of a generic type is expressed in a similar way. A mixed sequences of pairs of numbers can be expressed as List<Pair<? extends Number, ? extends Number>> or as Pair<? extends Number, ? extends Number>[] .
of any number type of any type of pair of numbers
collection List<Number> List<Pair<? extends
Number,? extends Number>>
array Number[] Pair<? extends Number,?
extends Number>[] *)
*) Legal as the type of reference variable, but illegal in a new expression.
The array type Pair<? extends Number, ? extends Number>[] needs further explanation. This type would in principle denote a mixed sequence of pairs of different type, but this array type is not overly useful. It can only be used for declaration of reference variables, while it must not appear in new expressions. That is, we can declare reference variables of type Pair<? extends Number, ? extends Number>[] , but the reference can never refer to an array of its type, because no such array can be created.

Example (of illegal array creation):

Pair<? extends Number, ? extends Number>[] makeNumberPairs(int size) {
   return new Pair<? extends Number, ? extends Number>[size]; // error
}


error: generic array creation
return new Pair<? extends Number, ? extends Number>[size];
       ^
By and large an array type such as Pair<? extends Number, ? extends Number>[] is not particularly useful, because it cannot refer to an array of its type. It can refer to an array of the corresponding raw type, i.e. Pair[], or to an array of a non-generic subtype, e.g. Point[] , where Point is a subclass of Pair<Double,Double> for instance. In each of these cases using a reference variable of type Pair<? extends Number, ? extends Number>[] offers
no advantage over using a reference variable that matches the type of the array being refered to. Quite the converse; it is error prone and should be avoided. This rules applies to all array types with a component type that is a concrete or bounded wildcard parameterized type. For details see ParameterizedTypes.FAQ104A and ParameterizedTypes.FAQ307A .

Note that arrays of unbounded wildcard parameterized types do not suffer from this restriction. The creation of an array of an unbounded wildcard parameterized type is permitted, because the unbounded wildcard parameterized type is a so-called reifiable type, so that an array reference variable with an unbounded wildcard parameterized type as its component type, such as Pair<?,?>[] , can refer to an array of its type.

Example (of legal array creation):

Pair<?,?>[] makeNumberPairs(int size) {
   return new Pair<?,?>[size]; // fine
}
LINK TO THIS #FAQ006
REFERENCES Can I create an object whose type is a wildcard parameterized type?
Can I create an array whose component type is a wildcard parameterized type?
Why is it allowed to create an array whose component type is an unbounded wildcard parameterized type?
Can I declare a reference variable of an array type whose component type is a concrete parameterized type?
Can I declare a reference variable of an array type whose component type is a bounded wildcard parameterized type?
Can I declare a reference variable of an array type whose component type is an unbounded wildcard parameterized type?
What is a reifiable type?

What is the difference between a Collection<Pair<String,Object>>, a Collection<Pair<String,?>> and a Collection<? extends Pair<String,?>>?

All three types refer to collections that hold pairs where the first part is a String and the second part is of an arbitrary type.  The differences are subtle.
The three parameterized types are relatively similar.  They all refer to collections that hold pairs where the first part is a String and the second part is of an arbitrary type. 

Let us start with a comparison of the two concrete parameterized types Collection<Pair<String,Object>> and Collection<Pair<String,?>> .  The both contain pairs where the first part is a String .  The individual pairs stored in the collection can for instance contain a String and a Date , or a String and an Object , or a String and a String . The difference lies in the types of the pairs that can be added to the two collections.

Example (using a Collection<Pair<String,Object>> ): 

Collection< Pair<String, Object > > c = new ArrayList<Pair<String,Object>>();

c.add(new Pair<String, Date >  ("today", new Date()));    // error: illegal argument type
c.add(new Pair<String, Object >("today", new Date()));    // fine

c.add(new Pair<String, String >("name","Pete Becker"));   // error: illegal argument type
c.add(new Pair<String, Object >( "name","Pete Becker" ));   // fine

The example demonstrates that only pairs of type Pair<String,Object> can be added to a Collection<Pair<String,Object>> .  A Collection<Pair<String,Object>> is a homogenous collections of elements of the same type.  The individual pairs may contain different things, as long as  the type of the pair is Pair<String,Object> .  For instance, a pair may consist of a String and a Date , but it must not be of type Pair<String,Date>

Example (using a Collection<Pair<String,?>> ): 

Collection< Pair<String, ? > > c = new ArrayList<Pair<String,?>>();

c.add(new Pair<String, Date >  ("today", new Date()));    // fine
c.add(new Pair<String, Object >("today", new Date()));    // fine

c.add(new Pair<String, String >("name","Pete Becker"));   // fine
c.add(new Pair<String, Object >( "name","Pete Becker" ));   // fine

The example illustrates that a Collection<Pair<String,?>> accepts all types of pairs as long as the first type argument is String . For instance, a pair of type Pair<String,Date> is accepted. A Collection<Pair<String,?>> is a heterogenous collections of elements of the similar types. 

The key difference between a Collection<Pair<String,Object>> and a Collection<Pair<String,?>> is that the first contains elements of the same type and the latter contains elements of different similar types. 
 
 

The type Collection<? extends Pair<String,?>> is fundamentally different. It is a wildcard parameterized type, not a concrete parameterized type.  We simply do not know what exactly a reference variable of the wildcard type refers to. 

Example (using a Collection<? extends Pair<String,?>> ): 

Collection< ? extends Pair<String, ? > > c = new ArrayList<Pair<String,?>>();

c.add(new Pair<String, Date >  ("today", new Date()));    // error: add method must not be called
c.add(new Pair<String, Object >("today", new Date()));    // error: add method must not be called

c.add(new Pair<String, String >("name","Pete Becker"));   // error: add method must not be called
c.add(new Pair<String, Object >( "name","Pete Becker" ));   // error: add method must not be called

The type Collection<? extends Pair<String,?>> stands for a representative from the family of all instantiations of the generic type Collection where the type argument is a subtype of type Pair<String,?> .   This type family includes members such as Pair<String,String> , Pair<String,Object> , Pair<String,? extends Number> , and Pair<String,?> itself . 

Methods like add must not be invoked through a reference of a wildcard type. This is because the add method takes an argument of the unknown type that the wildcard stands for.  Using the variable c of the wildcard type Collection<? extends Pair<String,?>> , nothing can be added to the collection.  This does not mean that the collection being refered to does not contain anything.  We just do not know what exactly the type if the collection is and consequently we do not know what type of elements it contains.  All we know is that is contains pairs where the first part is a String .  But we do not know of which type the second part of the pair is, or whether or not all pairs are of the same type. 


So far, we've silently assumed that Pair is a final class. What if it has subtypes?  Say, it has a subtype class SubTypeOfPair<X,Y> extends Pair<X,Y>

In that case, a Collection<Pair<String,Object>> may not only contain objects of type Pair<String,Object> , but also objects of type SubTypeOfPair<String,Object>

A Collection<Pair<String,?>> may not only contain objects of different pair types such as Pair<String,Date> and Pair<String,Object> , but also objects of subtypes of those, such as SubTypeOfPair<String,Date> and SubTypeOfPair<String,Object>

The type Collection<? extends Pair<String,?>> stands for a representative from the family of all instantiations of the generic type Collection where the type argument is a subtype of type Pair<String,?> .   This type family is now even larger.  It does not only include members such as Pair<String,String> , Pair<String,Object> , Pair<String,? extends Number> , and Pair<String,?> itself, but also type such as SubTypeOfPair<String,String> , SubTypeOfPair<String,Object> , SubTypeOfPair<String,? extends Number> , and SubTypeOfPair<String,?>
 

LINK TO THIS #FAQ006A
REFERENCES What is a bounded wildcard?
Which methods and fields are accessible/inaccessible through a reference variable of a wildcard type?
What is the difference between a Collection<?> and a Collection<Object>?
Which super-subset relationships exist among wildcards?

How can I make sure that a wildcard that occurs repeatedly in the same scope stands for the same type?


In general you can't.
If the same wildcard appears repeatedly, each occurrence of the wildcard stands for a potentially different type. There is no way to make sure that the same wildcard represents the same type. 

Example (using the same wildcard repeatedly): 

Pair< ? , ? > couple = new Pair< String , String >("Orpheus","Eurydike");
Pair< ? , ? > xmas   = new Pair< String , Date >("Xmas", new Date(104,11,24));
There is nothing you can do to make sure that a reference variable of type Pair<?,?> represents a pair of elements of the same type. 

Depending on the circumstances there might be work-arounds that achieve this goal. For instance, if the type Pair<?,?>   is the type of a method argument, it might be possible to generify the method to ensure that the method argument is a pair of elements of the same type. 

For instance, the following method 

void someMethod(Pair< ? , ? > pair) { ... }
accepts all types of pairs.  It is mostly equivalent to the following generic method: 
< X , Y > void someMethod(Pair< X , Y > pair) { ... }
In order to make sure that only pairs of elements of the same type are passed to the method, the method can be generified as follows: 
< T > void someMethod(Pair< T , T > pair) { ... }
Now it is guaranteed that the method accepts only pairs of elements of the same type.
LINK TO THIS #FAQ007
REFERENCES What is a wildcard parameterized type?
If a wildcard appears repeatedly in a type argument section, does it stand for the same type?

 

Using Generic Methods

Why doesn't method overloading work as I expect it?
 
Because there is only one byte code representation of each generic type or method.
When you invoke an overloaded method and pass an argument to the method whose type is a type variable or involves a type variable, you might observe surprising results.  Let us study an example. 

Example (of invocation of an overloaded method): 

static void overloadedMethod( Object o) {
        System.out.println("overloadedMethod(Object) called");
}
static void overloadedMethod( String s) {
        System.out.println("overloadedMethod(String) called");
}
static void overloadedMethod( Integer i) {
        System.out.println("overloadedMethod(Integer) called");
}

static <T> void genericMethod(T t) {
        overloadedMethod (t) // which method is called? 
}

public static void main(String[] args) {
        genericMethod( "abc" );
}

We have several overloaded versions of a method.  The overloaded method is invoked by a generic method which passes an argument of type  T to the overloaded method.  Eventually the generic method is called and a string is passed as an argument to the generic method. One might expect that inside the generic method the string version of the overloaded method is invoked, because the method argument is a string.  This, however, is wrong.

The program prints:
 

overloadedMethod( Object ) called


How can this happen?  We pass an argument of type  String to the overloaded method and yet the version for type  Object is called. The reason is that the compiler creates only one byte code representation per generic type or method and maps all instantiations of the generic type or method to that one representation. 

In our example the generic method is translated to the following representation:
 

void genericMethod( Object t) {
        overloadedMethod (t)
}


Considering this translation, it should be obvious why the  Object version of the overloaded method is invoked.  It is entirely irrelevant what type of object is passed to the generic method and then passed along to the overloaded method.  We will always observe a call of the  Object version of the overloaded method. 

More generally speaking:  overload resolution happens at compile time, that is, the compiler decides which overloaded version must be called. The compiler does so when the generic method is translated to its unique byte code representation.  During that translation type erasure is performed, which means that type parameters are replaced by their leftmost bound or  Object if no bound was specified.  Consequently, the leftmost bound or Object determines which  version of  an overloaded method is invoked.  What type of object is passed to the method at runtime is entirely irrelevant for overload resolution.



Here is another even more puzzling example.

Example (of invocation of an overloaded method):
 

public final class GenericClass<T> {

    private void overloadedMethod( Collection<?> o) {
        System.out.println(" overloadedMethod (Collection<?>)");
    }
    private void overloadedMethod( List<Number> s) {
        System.out.println(" overloadedMethod (List<Number>)");
    }
    private void overloadedMethod( ArrayList<Integer> i) {
        System.out.println(" overloadedMethod (ArrayList<Integer>)");
    }

    private void method(List<T> t) {
overloadedMethod(t);  // which method is called?
    }

    public static void main(String[] args) {
GenericClass <Integer> test = new  GenericClass < Integer >();
        test.method( new  ArrayList< Integer > () );
    }
}


The program prints:
 

overloadedMethod (Collection<?>)

One might have expected that version for  ArrayList<Integer> would be invoked, but that again is the wrong expectation.  Let us see what the compiler translates the generic class to. 

Example (after type erasure):
 

public final class GenericClass {

    private void overloadedMethod( Collection o) {
        System.out.println(" overloadedMethod (Collection<?>)");
    }
    private void overloadedMethod( List s) {
        System.out.println(" overloadedMethod (List<Number>)");
    }
    private void overloadedMethod( ArrayList i) {
        System.out.println(" overloadedMethod (ArrayList<Integer>)");
    }

    private void method(List t) {
overloadedMethod(t);
    }

    public static void main(String[] args) {
GenericClass test = new  GenericClass ();
        test.method( new  ArrayList () );
    }
}

One might mistakenly believe that the compiler would decide that the  List version of the overloaded method is the best match.  But that would be wrong, of course.  The  List version of the overloaded method was originally a version that takes a  List<Number> as an argument, but on invocation a  List<T> is passed, where  T can be any type and need not be a  Number . Since  T can be any type the only viable version of the overloaded method is the version for  Collection<?> .



Conclusion:
Avoid passing type variables to overloaded methods. Or, more precisely, be careful when you pass an argument to an overloaded method whose type is a type variable or involves a type variable.
LINK TO THIS #FAQ050
REFERENCES How does the compiler translate Java generics?
What is type erasure?
What is method overriding?
What is method overloading?
What is a method signature?
What is the @Override annotation?
What are override-equivalent signatures?
When does a method override its supertype's method?
What is overload resolution?

Why doesn't method overriding work as I expect it?
 
Because the decision regarding overriding vs. overloading is based on the generic type, not on any instantiation thereof.
Sometimes, when you believe you override a method inherited from a supertype you inadvertantly overload instead of override the inherited method.  This can lead to surprising effects.  Let us study an example.

Example (of overloading):
 

class Box <T> {
  private T theThing;
  public Box(
T t)        { theThing = t; }
  public void reset(
T t) { theThing = t; }
  ...
}
class WordBox< S extends CharSequence > extends Box< String > {
  public WordBox(
S t)    { super(t.toString().toLowerCase()); }
  public void reset(
S t) { super.reset(t.toString().toLowerCase()); } 
  ...
}
class Test {
    public static void main(String[] args) {
        WordBox<String> city = new WordBox<String>("Skogland");
        city.reset("Stavanger"); 
// error: ambiguous
    }
}

error: reference to reset is ambiguous, 
both method reset
(T) in Box<String> and method reset(T) in  WordBox<String> match
        city.reset("Stavanger");
            ^

In this example, one might be tempted to believe that the method  WordBox<String>.reset(String) overrides the superclass method  Box<String>.reset(String) .  After all, both methods have the same name and the same parameter types.  Methods with the same name and the same parameter types in a super- and a subtype are usually override-equivalent.  For this reason, we might expect that the invocation of the  reset method in the  Test class leads to the execution of the  WordBox<String>.reset(String) method.  Instead, the compiler complains about an ambiguous method call.  Why?

The problem is that the subclass's  reset method does not override the superclass's  reset method, but overloads it instead.  You can easily verify this by using the @Override annotation.

Example (of overloading):
 

class Box <T> {
  private T theThing;
  public Box(
T t)        { theThing = t; }
  public void reset(
T t) { theThing = t; }
  ...
}
class WordB ox <S extends CharSequence> extends Box <String> {
  public WordBox(
S t)    { super(t.toString().toLowerCase()); }
@Override 
  public void reset(
S t) { super.reset(t.toString().toLowerCase()); } 
  ...
}


error: method does not override a method from its superclass
        @Override 
         ^


When a method is annotated by an  @Override annotation, the compiler issues an error message if the annotated method does not override any of its supertype's methods.  If it does not override, then it overloads or hides methods with the same name inherited from its supertype.  In our example the  reset method in the generic  WordBox<S extends CharSequence> class overloads the  reset method in the parameterized  Box<String> class.

The overloading happens because the two methods have different signatures. This might come as a surprise, especially in the case of the instantation  WordBox<String> , where the two  reset methods have the same name and the same parameter type. 

The point is that the compiler decides whether a subtype method overrides or overloads a supertype method when it compiles the generic subtype, independently of any instantiations of the generic subtype.  When the compiler compiles the declaration of the generic  WordBox<S extends CharSequence>  class, then there is no knowledge regarding the concrete type by which the type parameter  S might later be replaced.  Based on the declaration of the generic subtype the two  reset methods have different signatures, namely  reset(String) in the supertype and  reset(S_extends_CharSequence) in the generic subtype. These are two completely different signatures that are not override-equivalent.  Hence the compiler considers them overloading versions of each other.

In a certain instantiation of the subtype, namely in  WordBox<String> , the type parameter  S might be replaced by the concrete type String.   As a result both  reset methods visible in  WordBox<String> suddenly have the same argument type.  But that does not change the fact that the two methods still have different signatures and therefore overload rather than override each other.

The identical signatures of the two overloading version of the  reset method that are visible in  WordBox<String>  lead to the anbiguitiy that we observe in our example. When the  reset method is invoked through a reference of type  WordBox<String> , then the compiler finds both overloading versions.  Both versions are perfect matches, but neither is better than the other, and the compiler rightly reports an ambiguous method call.



Conclusion:
Be careful when you override methods, especially when generic types or generic methods are involved.  Sometimes the intended overriding turns out to be considered overloading by the compiler, which leads to surprising and often confusing results.  In case of doubt, use the  @Override annotation.
LINK TO THIS #FAQ051
REFERENCES How does the compiler translate Java generics?
What is type erasure?
What is method overriding?
What is method overloading?
What is a method signature?
What is the @Override annotation?
When does a method override its supertype's method?
Can a method of a generic subtype override a method of a generic supertype?

Coping With Legacy

What happens when I mix generic and non-generic legacy code?
 
The compiler issues lots of "unchecked" warnings.
It is permitted that a generic class or method is used in both its parameterized and its raw form.  Both forms can be mixed freely.  However, all uses that potentially violate the type-safety are reported by means of an "unchecked warning".  In practice, you will see a lot of unchecked warnings when you use generic types and methods in their raw form. 

Example (of mixing paramterized and raw use of a generic type): 

interface Comparable<T> {
  int compareTo(T other);
}
class SomeClass implements Comparable {
  public int compareTo(Object other) {
    ...
  }
}
class Test {
  public static void main(String[] args) {
    Comparable x = new SomeClass();
    x.compareTo(x);     // "unchecked" warning
  }
}


warning: [unchecked] unchecked call to compareTo(T) as a member of the raw type java.lang.Comparable
        x.compareTo(x);
                   ^
The Comparable interface is a generic type.  Its raw use in the example above leads to "unchecked" warnings each time the compareTo method is invoked. 

The warning is issued because the method invocation is considered a potential violation of the type-safety guarantee.  This particular invocation of compareTo is not unsafe, but other methods invoked on raw types might be. 

Example (of type-safety problem when mixing parameterized and raw use): 

class Test {
  public static void someMethod( List list) {
    list.add("xyz");     // "unchecked" warning
  }
  public static void test() {
    List<Long> list = new ArrayList<Long> ();
    someMethod(list);
  }
}


warning: [unchecked] unchecked call to add(E) as a member of the raw type java.util.List
     list.add("xyz");
             ^
Similar to the previous example, the invocation of the add method on the raw type List is flagged with an "unchecked" warning.  The invocation is indeed unsafe, because it inserts a string into a list of long values. 

The compiler cannot distinguish between invocations that are safe and those that are not.  It reports "unchecked" warnings just in case that a call might be unsafe.  It applies a simple rule: every invocation of a method of a raw type that takes an argument of the unknown type that the class's type parameter stands for, is potentially unsafe.  That does not mean, it must be unsafe (see Comparable.compareTo ), but it can be unsafe (see List.add ). 

If you find that you must intermix legacy and generic code, pay close attention to the unchecked warnings. Think carefully how you can justify the safety of the code that gives rise to the warning. Once you've made sure the warning is harmless suppress it using the SuppressWarnings annotation. 

If you can re-engineer existing code or if you write new code from scratch you should use generic types and methods in their parmeterized form and avoid any raw use.  For instance, the examples above can be "repaired" as follows: 

Example #1 (corrected): 

interface Comparable<T> {
  int compareTo(T other);
}
class SomeClass implements Comparable <Object> {
  public int compareTo(Object other) {
    ...
  }
}
class Test {
  public static void main(String[] args) {
    Comparable <Object> x = new SomeClass();
    x.compareTo(x);     // fine
  }
}
No "unchecked" warning occurs if the Comparable interface is used in its parameterized form in all places. 

Example #2 (corrected): 

class Test {
  public static void someMethod( List <String> list) {
    list.add("xyz");     // fine
  }
  public static void test() {
    List<Long> list = new ArrayList<Long> ();
    someMethod(list);   // error
  }
}


error: someMethod(java.util.List<java.lang.String>) cannot be applied to java.util.List<java.lang.Long>)
        someMethod(list);
        ^
The "unchecked" warning in someMethod is no longer necessary if the generic type List is used in its parameterized form as List<String> .  With this additional type information the compiler is now capable of flagging the formerly undetected type-safety problem in method test as an error.
LINK TO THIS #FAQ101
REFERENCES What does type-safety mean?
What is the raw type?
Can I use a raw type like any other type?
What is an "unchecked" warning?
How can I disable or enable unchecked warnings?
What is the SuppressWarnings annotation?

Should I re-engineer all my existing types and generify them?


No, most likely not.
Not all types are inherently generic.  There is no point to turning a type into a generic type if the type does not semantically depend on a particular unknown type that can be more adequately be expressed by means of a type parameter. 

Example (of an arbitrary non-generic type taken from package org.w3c.dom ): 

public interface NameList {
  boolean  contains(String str);
  boolean  containsNS(String namespaceURI, String name);
  int      getLength();
  String   getName(int index);
  String   getNamespaceURI(int index);
}
The NameList interface takes and returns either strings or primitive types and there is no reason why this class should be generic in any form. 

Other non-generic types would benefit from generics. 

Example (of another arbitrary non-generic type): 

public interface Future {
  boolean  cancel(boolean mayInterruptIfRunning);
  Object    get();
  Object    get(long timeout, TimeUnit unit);
  boolean  isCancelled();
  boolean  isDone();
}
This interface has get methods that return Object references.  If these methods return the same type of object for a given instance of type Future , then the interface is more precisely declared as a generic interface. 

Example (of corresponding generic type): 

public interface Future <V> {
  boolean  cancel(boolean mayInterruptIfRunning);
  V         get();
  V         get(long timeout, TimeUnit unit);
  boolean  isCancelled();
  boolean  isDone();
}

Occasionally, the generification of one type leads to the generification of other related types. 

Example (of non-generic types taken from package java.lang.ref in JDK 1.4): 

public class ReferenceQueue {
  public ReferenceQueue() { }
  public Reference poll() { ... }
  public Reference remove(long timeout) 
    throws IllegalArgumentException, InterruptedException { ... }
  public Reference remove() 
    throws InterruptedException { ... } 
}
public abstract class Reference {
  private Object referent; 
  ReferenceQueue queue;
  Reference next;
  Reference( Object referent) { ... }
  Reference( Object referent, ReferenceQueue queue) { ... }
  public void clear() { ... }
  public boolean enqueue() { ... }
  public Object get() { ... }
  public boolean isEnqueued() { ... }
}
The abstract class Reference internally holds a reference of type Object and has methods that take and return Object references.  If these methods take and return the same type of object that is held internally, then the class is more precisely declared as a generic class, namely as Reference<T> where T is the type of the referent.

When we decide to parameterize class Reference then we must provide type arguments in all places where type Reference is used.  This affects class ReferenceQueue because it has methods that return references of type Reference .  Consequently, we would declare class ReferenceQueue as a generic class, too. 

Once we have generified class ReferenceQueue then we must return to class Reference and provide type arguments in all places where type ReferenceQueue is used. 

Example (of corresponding generic type in JDK 5.0): 

public class ReferenceQueue <T