| By Jess Garms, Tim Hanson | Article Rating: |
|
| February 6, 2006 11:30 AM EST | Reads: |
33,217 |
If this were to use arrays, the interface could return Number[] and the implementation could return Integer[].
Lower Bounds
We've talked mostly about upper bounded wildcards. There is also a lower bounded wildcard. A List<? super Number> is a list whose exact "element type" is unknown, but it is number or a super type of number. So it could be a List<Number> or a List<Object>.
Lower bounded wildcards are not nearly as common as upper bounded wildcards. But when you need them, they are essential.
Lower vs Upper Bounds
List<? extends Number> readList = new ArrayList<Integer>();
Number n = readList.get(0);
List<? super Number> writeList = new ArrayList<Object>();
writeList.add(new Integer(5));
The first list is a list that you can read numbers from. The second list is a list that you can write numbers to.
Unbounded Wildcard
Finally, the List<?> is a list of anything. Almost the same as List<? Extends Object>. You can always read Objects, but you cannot write to the list.
Wildcards in Public APIs
To summarize, wildcards are great for hiding implementation details from callers as we saw a few slides back, but even though lower bounded wildcards appear to provide read-only access, they do not due to non-generic methods like remove(int position). If you want a truly immutable collection, use the unmodifiableCollection(), etc.
Be aware of wildcards when writing APIs. In general, you should try to use wildcards when passing generic types. It makes the API accessible to a wider range of callers.
In this example, by accepting a List<? extends Number> instead of List<Number>, the method can be called by many different types of lists:
void removeNegatives(List<? extends Number> list);
Constructing Generic Types
Now we'll cover constructing your own generic types. I'll show example idioms where type safety can be improved by using generics, as well as common problems that occur when trying to implement generic types.
Collection-Like Functions
This first example of a generic class is a collection-like example. Pair has two type parameters, and the fields are instances of the types:
public final class Pair<A,B> {
public final A first;
public final B second;
public Pair(A first, B second) {
this.first = first;
this.second = second;
}
}
This makes it possible to return two items from a method without having to write special-purpose classes for each two-type combo. The other thing you could have done is return Object[], which isn't type-safe or pretty.
In the usage here, we return a File and a Boolean from a method. The client of the method can use the fields directly without casting:
public Pair<File,Boolean> getFileAndWriteStatus(String path){
// create file and status
return new Pair<File,Boolean>(file, status);
}
Pair<File,Boolean> result = getFileAndWriteStatus("...");
File f = result.first;
boolean writeable = result.second;
Beyond Collections
Here is an example where generics are used for additional compile-time safety. By parameterizing the DBFactory class by the type of Peer it creates, you are forcing Factories to return a specific subtype of Peer:
public abstract class DBFactory<T extends DBPeer> {
protected abstract T createEmptyPeer();
public List<T> get(String constraint) {
List<T> peers = new ArrayList<T>();
// database magic
return peers;
}
}
By implementing DBFactory<Customer>, the CustomerFactory is forced to return a Customer from createEmptyPeer:
public class CustomerFactory extends DBFactory<Customer>{
public Customer createEmptyPeer() {
return new Customer();
}
}
Generic Methods
Whenever you want to place constraints on a generic type between parameters or a parameter and a return type, you probably want to use a generic method.
For example, if you write a reverse function that reverses in place, you don't need a generic method. However, if you want reverse to return a new list, you'd like the element type of the new list to be the same as the list that was passed in. In that case, you need a generic method:
<T> List<T> reverse(List<T> list)
Reification
When implementing a generic class, you may want to construct an array, T[]. Because generics is implemented by erasure, this is not allowed.
You might try to cast an Object[] to T[]. This is not safe.
Reification - Solution
The solution, courtesy of the generics tutorial, is to use a "Type Token". By adding a Class<T> parameter to the constructor, you force clients to supply the correct class Object for the type parameter of the class:
public class ArrayExample<T> {
private Class<T> clazz;
public ArrayExample(Class<T> clazz) {
this.clazz = clazz;
}
public T[] getArray(int size) {
return (T[])Array.newInstance(clazz, size);
}
}
To construct an ArrayExample<String>, the client would have to pass String.class to the constructor because the type of String.class is Class<String>.
Having the class objects makes it possible then to construct an array with exactly the right element type.
Migrating to Generics
Finally, we'll just briefly talk about migrating 1.4 code to using Generics:
- You can generify existing classes and interfaces.
- You can convert raw collection uses to generic collections, even in public methods. This will not break clients who override.
- If you need to pass a collection to a 1.4-level library, you can use checked collections. These will fail fast if that library attempts to put something in a collection that shouldn't belong. This is an interesting example of the "Type Token" pattern we mentioned.
- In general, if you want to know if something is safe, look at the standard libraries. There are plenty of examples of migrating classes while maintaining source and binary compatibility.
In summary, the new language features make for a substantial change to Java. By understanding when and how to use them, you'll write better code.
Published February 6, 2006 Reads 33,217
Copyright © 2006 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Jess Garms
Jess Garms works at BEA Systems.
More Stories By Tim Hanson
Tim Hanson is the Javelin compiler architect at BEA Systems. Tim developed much of BEA's Java compiler - one of the earliest 1.5-compliant implementations. He has written numerous other compilers, including a CORBA/IDL compiler while at IBM, and an XQuery compiler.
![]() |
SYS-CON Brazil News Desk 02/06/06 11:31:53 AM EST | |||
During the beta period for JDK 1.5, we worked on a 1.5 Java compiler for BEA's Java IDE. As we implemented various new features, people would begin exploiting them in new ways, some clever, some clearly candidates for a list of what not to do. The compiler itself used 1.5 features, so we gained direct experience in maintaining 1.5 code as well. |
||||
![]() |
SYS-CON India News Desk 02/06/06 10:49:34 AM EST | |||
During the beta period for JDK 1.5, we worked on a 1.5 Java compiler for BEA's Java IDE. As we implemented various new features, people would begin exploiting them in new ways, some clever, some clearly candidates for a list of what not to do. The compiler itself used 1.5 features, so we gained direct experience in maintaining 1.5 code as well. |
||||
- Kindle 2 vs Nook
- Why IBM’s Server Chief Got Busted
- Is Cloud Computing Like Teenage Sex?
- Industry Experts Discuss the State of Cloud Computing
- Performance Tuning Essentials for Java
- Confessions of a Ulitzer Addict
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- It's the Java vs. C++ Shootout Revisited!
- Cloud Computing Can Revitalize Your Career as Software Developer
- IBM Could "Reinvent" Java: Mills
- Oracle & Cloud Computing: Exclusive Q&A with SVP Richard Sarwal
- A Brief History of Cloud Computing
- Kindle 2 vs Nook
- Cloud CEOs, CTOs & SVPs to Speak at 4th International Cloud Computing Expo
- Why IBM’s Server Chief Got Busted
- Is Cloud Computing Like Teenage Sex?
- Industry Experts Discuss the State of Cloud Computing
- Performance Tuning Essentials for Java
- The Difference Between Web Hosting and Cloud Computing
- Cloud Computing Expo: Exclusive Q&A with Yahoo! SVP Cloud Computing
- Ajax in RichFaces 3.3, JSF 2 and RichFaces 4
- Confessions of a Ulitzer Addict
- My Thoughts on Ulitzer
- Tactical Cloud Computing Panel at 1st Annual GovIT Expo
- A Cup of AJAX? Nay, Just Regular Java Please
- Java Developer's Journal Exclusive: 2006 "JDJ Editors' Choice" Awards
- The i-Technology Right Stuff
- JavaServer Faces (JSF) vs Struts
- Rich Internet Applications with Adobe Flex 2 and Java
- Java vs C++ "Shootout" Revisited
- Bean-Managed Persistence Using a Proxy List
- Reporting Made Easy with JasperReports and Hibernate
- Creating a Pet Store Application with JavaServer Faces, Spring, and Hibernate
- What's New in Eclipse?
- Why Do 'Cool Kids' Choose Ruby or PHP to Build Websites Instead of Java?
- i-Technology Predictions for 2007: Where's It All Headed?









































