Home arrow Java arrow Page 2 - Wildcards, Arrays, and Generics in Java
JAVA

Wildcards, Arrays, and Generics in Java


In this conclusion to a five-part series, you will learn about wildcards, arrays, and more. This article was excerpted from chapter eight of the book Learning Java, third edition, written by Patrick Niemeyer and Jonathan Knudsen (O'Reilly; ISBN: 0596008732). Copyright © 2006 O'Reilly Media, Inc. All rights reserved. Used with permission from the publisher. Available from booksellers or direct from O'Reilly Media.

Author Info:
By: O'Reilly Media
Rating: 5 stars5 stars5 stars5 stars5 stars / 10
June 07, 2007
TABLE OF CONTENTS:
  1. · Wildcards, Arrays, and Generics in Java
  2. · Wildcard Types Versus Generic Methods
  3. · Using Array Types
  4. · Case Study: The Enum Class
  5. · Case Study: The sort() Method

print this article
SEARCH DEVARTICLES

Wildcards, Arrays, and Generics in Java - Wildcard Types Versus Generic Methods
(Page 2 of 5 )

You'll recall that trying to work with an object through a wildcard instantiation of its generic type limits us to "reading" the object. We cannot "write" types to the object because its parameter type is unknown. In contrast, because generic methods can infer or capture an actual type for their arguments, they allow us to do a lot more with broad ranges of types than we could with wildcard instantiations alone.

For example, suppose we wanted to write a utility method that swaps the first two elements of a list. Using wildcards, we'd like to write something like this:

  // Bad implementation
 
List<?> swap( List<?> list ) {
     
Object tmp = list.get(0);
     
list.set( 0, list.get(1) ); // error, can't write
     
list.set( 1, tmp ); // error, can't write
     
return list;
  }

But we are not allowed to call the set() method of our list because we don't know what type it actually holds. We are really stuck and there isn't much we can do. But the corresponding generic method gives us a real type to hang our hat on:

  <T> List<T> swap( List<T> list ) {
      T tmp = list.get( 0 );
      list.set( 0, list.get(1) );
      list.set( 1, tmp );
      return list;
 
}

Here, we are able to declare a variable of the correct (inferred) type and write using the set() methods appropriately. It would seem that generic methods are the only way to go here. But there is a third path. Wildcard capture, as described in the previous section, allows us to delegate our wildcard version of the method to our actual generic method and use it as if the type were inferred, even though it's open-ended:

  List<?> swap( List<?> list ) {
     
return swap2( list ); // delegate to generic form
  }

Here, we renamed the generic version as swap2() and delegated.

Arrays of Parameterized Types

There is one place where we haven't yet considered how generic types affect the Java language: array types. After everything we've seen, it would seem natural to expect that arrays of generic types would come along for the ride. But as we'll see, Java has a schizophrenic relationship with arrays of parameterized types.

The first thing we need to do is recall how arrays work for regular Java types. An array is a kind of built-in collection of some base type of element. Furthermore, array types (including all multidimensional variations of the array) are true types in the Java language and are represented at runtime by unique class types. This is where the trouble begins. Although arrays in Java act a lot like generic collections (they change their APIs to adopt a particular type for "reading" and "writing"), they do not behave like Java generics with respect to their type relationships. As we saw in Chapter 6, arrays exist in the Java class hierarchy stemming from Object and extending down parallel branches with the plain Java objects.

Arrays are covariant subtypes of other types of arrays, which means that, unlike concrete generic types, although they change their method signatures, they are still related to their parents. This means that Strings [] in Java is a subtype of Object []. This brings up the aliasing problem that we mentioned earlier. An array of Strings can be aliased as an array of Objects and we can attempt to put things into it illegally that won't be noticed until runtime:

  String [] strings = new String[5];
  Object [] objects = strings;
  objects[0] = new Date(); // Runtime ArrayStoreException!

To prevent disaster, Java must check every array assignment for the correct type at runtime. But recall that generic types do not have real representations at runtime; there is only the raw type. So Java would have no way to know the difference between a Trap<Mouse> and a Trap<Bear> element in an array once the array was aliased as, say, an Object []. For this reason, Java does not allow you to create arrays of generic types--at least not concrete ones. (More on that later in this chapter.)


blog comments powered by Disqus
JAVA ARTICLES

- Java Too Insecure, Says Microsoft Researcher
- Google Beats Oracle in Java Ruling
- Deploying Multiple Java Applets as One
- Deploying Java Applets
- Understanding Deployment Frameworks
- Database Programming in Java Using JDBC
- Extension Interfaces and SAX
- Entities, Handlers and SAX
- Advanced SAX
- Conversions and Java Print Streams
- Formatters and Java Print Streams
- Java Print Streams
- Wildcards, Arrays, and Generics in Java
- Wildcards and Generic Methods in Java
- Finishing the Project: Java Web Development ...

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2014 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials