All the Java Collection classes, e.g. HashMap, ArrayList, TreeList can contain only generic Objects. The problem with this is you must keep track manually what sorts of object are really in each Collection. The compiler won’t warn you if you add a Cat to a Collection of Dogs.
Without genericity, in Java, you must, at run time, cast objects on the way into a Collection to make sure they are the right type and cast them back again on the way out before you can use their methods. It is totally up to you as application programmer to enforce your rules about what sort of objects you want in each Collection. You can’t simply declare that a Collection will contain only Dog objects and have attempts put anything else in flagged at compile time.
Java version 1.5 or later has generics implemented with high overhead, requiring implicit casts both on the way into the collection and on the way out. The compiler automatically casts all objects going into your collection to Dog and will automatically cast them back to Dog on the way out. Inside the collection, they are treated as generic Objects.
In theory, neither of these two time consuming casts are necessary. However, removing them would create a vulnerability in the JVM (Java Virtual Machine) that could be exploited maliciously. The saving grace of the design in that Sun did not need to change the JVM or class file structure to implement it.
You can try out the Java version 1.5 or later compiler with generics.
Further, types passed to a static method define the types of the parameters in the call, something quite different from passing a class as a parameter, which could only have an effect once the call had been made, e.g.
The theoretical magical property of the new syntax is that users of new generified classes need not change their source code, or even recompile. This was done so that Java version 1.5 source could run on old 1.4 JVMs (Java Virtual Machines). Generics jumped through hoops to maintain compatibility with the old JVMs and class files. However, in practice, for other reasons, it turns out Java version 1.5 code won’t run on old JVMs. If you do decide to use generics in your code that calls the new generic Collection classes for example, you only need to change your variable declarations and where you instantiate objects. All the other code can stay identical, though many casts then become unnecessary. You really only need to understand generics to any extent when you write your own parameterised classes, usually containers of some sort. There is nothing to do for code that uses those classes, other than fix the errors the type checking uncovers.// You MAY NOT write code like this: HashMap<String,Integer>[] hs = new HashMap<String,Integer>[1000];This is nuts since all the Collection classes fundamentally depend on internally typed arrays. Astoundingly, you can’t write code that involves arrays and generics without generating (or suppressing) unchecked conversion warnings. Even Oracle’s Collection code generates warnings! The design of generics is so jerry-rigged, so inept that generics can’t even handle the very specific purpose they were designed for, namely Collection type safety!!! The excuse Sun gives is this goofiness is necessary because of type erasure — that all generic type information is checked then discarded at compile time. The excuse they give for type erasure was they wanted to make code with generics usable by older Java object code that knew nothing of genericity. You can’t actually do this, so the benefit was never realised.
Type erasure implies many peculiar restrictions:
You
javac.exe -source 1.5 -target 1.5 *.java
to turn on generics. Otherwise they will be treated as syntax errors.
To create an ArrayList that can only hold Dog Objects. If you attempt to put anything else in there, (except subclasses like Dalmatians), you will find out at compile time. This is a great improvement on the old days when you sometimes found out about your errors when you partly exercised the code at run time.
This is all very well for container classes that treat their contents as simple Objects and never execute any methods on them. But what if you had a smart container that wanted to run some of the Dog methods on its contents? Then you would have to say something like this where D stands for the class of the variable type of the container. You define your new Kennel container that can only hold Dogs or their// this is NOT legal java.util.Vector<Dog> dogs = new java.util.Vector<Dalmatian>();
// naive and unsuccessful attempt to create a new object of generic type T T thing = new T();This fails because of type erasure. All trace of generics disappears at run time leaving just raw objects. The runtime
// What that code compiles to at run time: Object thing = new Object();To get the effect of being able to create an object of an arbitrary class you need to pass a Class Object parameter and use reflection with newInstance. Further, your construction classes need to have no-argument constructors. Generics are extremely subtle and difficult. One shortcut is to think of a Sun class that has similar generics to one you are writing and have a peek at the source code in src.zip to see how Sun pulled it off, e. g. If you wanted to use an enum as a generic qualifier, see how EnumSet did it. To see how to allocate an array of a generic type T, see how Angelika Langer’s Generics FAQ for details on how the kludges work.
// How the sort method is defined in Collections.sort // Quite a bit more complex that using it, eh? public static <T extends Comparable<? super T>> void sort( List<T> list )The sort static method is designed to work with a class T that implements Comparable on T or some superclass of T, e.g. Object. (Infuriatingly, generics use the term extends when they really mean implements). The method wants to sort a List of such T class objects.
You would expect to invoke it then with:
However, the compiler is smart enough most of the time to guess the type(s) from the context. In this case the compiler knows that listOfDogs is a List< Dog> therefore the mysterious class T must be Dog. The compiler gets clues from the types of the parameters and suprisingly from the type on the left hand side of the equal sign which it matches with the return type allowing you to get away with the short form:// Short form of sort invocation // relying on compiler static type inference Collections.sort( listOfDogs );
So when is Java smart enough to figure out the types on its own via inferring? It sometimes feels as if it depends on the phases of the moon. Inferring has even the cleverest programmers scratching their heads. Nobody can figure out for certain why sometimes the compiler can infer the generic types and sometimes it cannot. So what can you do?
If you have Eclipse, you can rapidly experiment, removing the explicit types one by one and putting them back if Eclipse complains. If you don’t have Eclipse, you can do the same thing more slowly with a compile cycle.
The problem with removing type tags is if you remove one too many tags, you are flying without a net. You have effectively turned off type checking. It is difficult to tell the difference between allowing inference to check types and turning off type checking altogether. This is a serious flaw in the design of Java generics.
Generic type tags are useful documentation to let others know what your code is up to. That is an argument for leaving them in.
If you burn the generic types into your code in 100 places, it will be hard to modify later if you change that type. Ideally you should specify the type of a variable in only one place — where it is declared. That is an argument for removing the type tags wherever you can.
Code like this will cause problems:
// generates type mismatch error ArrayList<Thing> things = ois.readObject();
You can try to fix it with a cast like this:
// generates cast warning ArrayList<Thing>things = (ArrayList<Thing>)ois.readObject();
but that generates a warning message. The problem is type erasure. The generic type is not stored with the serialized object. Java could check that the Object read back was an ArrayList, but not that it was an ArrayList< Thing>. Since it can’t guarantee, it gives the warning. The problem is the lame type erasure way generics were implemented. Had the type information been included, Java could check and the cast would be valid. So what do you do? You can just live with the warning, suppress it with an annotation like this:
// suppress unchecked warning @SuppressWarnings( "unchecked" ) void restore() { // Java cannot check that the object is actually an ArrayList<Thing>. // It will just trust that it is. ArrayList<Thing> things = (ArrayList<Thing>) ois.readObject(); ... }
or you can copy the fields one by one like this:
If your ArrayList is already allocated and final, you can do it this way:
// copy with a temporary array, generates no warning final ArrayList<Thing> things = new ArrayList<Thing>( INITIAL_SIZE ); ... final ArrayList<Object> temp = (ArrayList<Object>)ois.readObject(); things.clear(); for ( Object item : temp ) { things.add( (Thing)item ); }
It is much simpler to read and write serialized arrays than ArrayLists. They don’t have this problem since you are not relying on generics for your type information. For arrays, the Java type system embeds the actual type in the ObjectStream. The problem is you may not be able to switch your ObjectStream ArrayLists to simple arrays when your clients have many files in the old serialized ArrayList format. Arrays are also slightly more compact.
ArrayList<Dog> is a collection permitted to contain Dogs or any subclass of Dog. An ArrayList< Dog> that incidentally contained only Dalmatians is a quite different beast from an ArrayList< Dalmatian> which can’t contain anything but Dalmatians (or their subclasses).
Collection<Object> is a heterogenous Collection, while Collection<?> is a homogenous Collection of elements of the same unknown type, e.g. Dog and its subclasses.
Consider the wildcard form of a type specification:
The wildcard form restricts our ability to put raw Dog objects into the Collection, but on the other hand it lets us deal with Collection< Dalmatian>, where we could not otherwise.
You will need to read Oracle’s tutorial many times. It is as subtle as a Buddhist sutra. It makes me wonder if generics were a big mistake, introducing something so very difficult to solve a simple problem. Angelika Langer’s Generics FAQ is somewhat more accessible. Just keep reading and experimenting and more and more of what you read will make sense little by little. Unfortunately, I find the understanding does not stick and you have to keep going back to the well to have it continue to make sense.
Here is a complex example. If you understand this, you will be well on your way to understanding the fine points:
public static <D extends Dog & Comparable<? super D>> D selectSuitableDog( Collection<? extends D> );Means:
This static method above is designed to be used with class D that has the following properties:
You must pass a Collection to the method where the Collection contains Dog objects (where the Dog objects may be subclasses of Dog), or a more limited Collection of some subclass of Dog objects, e.g. a Collection< Dalmatian> of pure Dalmatian objects. Note that a Collection< Dog> where all elements happen to be Dalmatian is quite a different animal from a Collection< Dalmatian>where all elements are coerced to be Dalmatians (or subsets of Dalmatian).
Compared with the gobbledegook to define the method, your call to the method is very simple:
It helps to understand generics by thinking in terms of containers — most generified types are containers/Collections in some form or other.
Generified
public class Container<T> {}The T represents a type. The implementer of Container has no idea what type it is, it’s just some type, any type. Since we don’t know what it is, all we can guarantee is that it is an Object of some type (all non-primitive types are a subclass of Object and generics don’t use primitive types), so wherever T is found in the implementation, you can mentally replace it with Object for the same effect.
Sometimes, though, we don’t want to let people include any old object. To do this, we declare an
public class Container<T extends Number> {}
If you think of a class hierarchy with the basic root classes at the top and the subclasses dangling down from it, then the upper bound is the name of the root uppermost class of a branch that is valid for T.
Now only Numeric types can be stored in the container. Also, since we know that any given value of T has to be a subclass of Number, we can safely reference objects in the container as Numbers instead of Objects.
Again, if you think of a class hierarchy with the basic root classes at the top and the subclasses dangling down from it, then the lower bound is the name of the lowermost class in a chain of superclasses that is valid for T. The bound includes the class mentioned, not just its super classes.
static <T> void sort( List<T> list, Comparator<? super T> c )
The above example says that for example, you could sort a List< Dalmatian> with either a Comparator< >Dalamatian> or a Comparator< Dog>.
To use generics, you merely have to replace the appropriate type parameter with your class. So a Container for Integers is declared as Container< Integer> (again primitive types are not valid here; this is due to implementation necessities.
Happily Java version 1.5 or later autoboxes primitive types in method calls allowing you to simulate containers of primitives.
Conversely, since we don’t know what type a Container< ?> holds, we can’t store stuff inside the container.
Otherwise we might accidentally store an Object in the Container of a type that does not belong.
However, since we know that all Containers must store Objects, we can treat whatever is in the Container as an Object. In effect, the wildcard turns the Container into a read-only object: you can’t write into Container< ?>, but you can read from it. This is internally enforced by the special subtyping rules of generic objects; the exact mechanisms require some mathematical theory that I will not delve in here.
Similarly to how we limited the storage type of a container with the extends Number relationship, we can limit the type of a wildcard. A type Container<? extends Number>' indicates that the object stores something that is at least of type Number. Once again, that means that instead of viewing it as containing something that is at least an Object, we can see it as containing something that is at least a Number.
Keep in mind the difference between a <Number> container that just incidentally contains only Integer objects and an <Integer> container that is restricted by generic type constraints to only Integer objects.
public class Foo<T extends Foo<T>> {}
You will see recursive types used in the definition of the Enum class that underlies enums.
However, be careful not to think of the generic parameter declaration as any kind of operation.
public class Foo<T extends Foo<T>> {}is not an operation. It is an assertion about the limitations on the type.
You generally subclass or implement such
public class Bar extends Foo<Bar> {}
The primary purpose of a recursive type is to allow the creation of generic interfaces whose methods require the use of the implementing class as parameters.
The other main use of lower bounds is in recursive types. Specifying
<T extends A<T>>is
<T extends A<? super T>>is typically more correct.
public static <T> T move( Container<T> from, Container<? super T> to);Here, you also saw an example of the use of the lower bounds. We want to be able to take an Integer stored in a Container< Integer> and put it into a Container< Number>. Using upper bounds is also possible here, but if we were to do that, you would extract a Number and not an Integer from the container. The object being moved is already known to be a Number, so we should we unnecessarily restrict the type of return?
This material comes compliments of Lew, a frequent contributor to comp.lang.java.programmer. The comments in green are mine.
Generics and arrays do not mix well. That’s because arrays remember their underlying type at runtime, but generics just become plain Objects at runtime through the process of type erasure†.
The compiler will not let you create an array of generic types, unless the generic parameter comprises entirely unadorned wildcard (?) characters. So
// legal Foo<?> [] bunchaFoos = new Foo<?> [NUMFOOS];
is legal, but
// illegal Foo<Bar> [] bunchaFoos = new Foo<Bar> [NUMFOOS];
is not. Other things like casting and reflection get really difficult, too.
For almost everything you want to do mixing arrays and generics you can use ArrayList instead of an array. The syntax is a little more verbose, and the code is somewhat slower, but the type safety and expressiveness compensate.
† In technical terms, an array is a reifiable type — in that it can be made real in the JVM. Consequently its base type must also be reifiable. A generic type, except for the pure wildcard ? generics, is not reifiable because of erasure. So the compiler won’t let you make an array of a generic type.
If you look at Oracle’s code for ArrayList and other generic-supporting classes, you might be surprised to find code that generates unchecked warnings (generics violated). There is no legitimate way to allocate arrays of generics. So what we do is sweep this unclean code under the rug and let ArrayList do the dirty deed for us. At least our code is clean.
The popular wisdom is you can’t have an array of HashMaps. Actually, you can, it is just it is not kosher generics.
// HashMap kludge. This will compile. HashMap<Long,String> hashMaps = new HashMap[ 1000 ]; // you may not write HashMap<Long,String> hashMaps = new HashMap<>[ 1000 ]; // or HashMap<Long,String> hashMaps = new HashMap<Long,String>[ 1000 ];
Mark Vedder made a stab at explaining why: In Java, arrays are covariant but generics are not. Array covariance has been present since Java version 1.0. When generics were added in Java version 1.5, they were made invariant since generics were implemented to ensure type safety at compile time. Given that arrays are covariant, that is possible that not all slots of the array will contain identical types as long as the type put into the slot inherits from the type the array represents. For example, putting a String and a Date in an Object[] array, or a String and a StringBuilder in a CharSequence[] array. If the type put into the array is not in the type hierarchy of the array, for example putting a Date into a String[] array, an ArrayStoreException is thrown.
This is a Runtime exception. So the issue is not caught until Runtime. With generics, it would be caught at compile time.
What are you supposed to do instead of using an array of HashMaps?
Use a List<Set<YourType>> backed by an ArrayList of HashMaps.
I think he meant Map not Set.
I have read these explanations many times and I still don’t get it. It is not so much how it works, but why syntax whose meaning seems clear to humans does not work. Why is it broken? Was it really impossible to do properly? I suspect some of these strange properties of generics came from going for a simple implementation (avoiding any run time implementation), rather than a logical one. Or it may have happened because generics were tacked on later to Java’s arrays. Arrays are not considered Collections, even though they share many characteristics.
Let us say you had a Set of Dalmatians each of which implemented the Dog interface and your method wanted a Set of Dogs, not a Set of Dalmatians. What do you do?
recommend book⇒Learning Java, fourth edition | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
by | Patrick Niemeyer and Jonathan Knudson | 978-1-4493-1924-3 | paperback | |||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
publisher | O’Reilly | 978-1-4493-7249-1 | eBook | |||||||||||||||||||||||||||||||||||||||||||||||||||||
published | 2013-06-25 | B00DDZPC9I | kindle | |||||||||||||||||||||||||||||||||||||||||||||||||||||
Covers Java 1.7 though nearly all of it is about older features, including enums and generics. Covers serialisation vs code generation. Particularly good at explaining the use of the Java 1.2 Collection classes. Teaches with example code, my favourite technique. It has a tiger on the cover because Oracle’s code name for Java 1.5 was Tiger. Contains a very good chapter on generics. The book is not for people new to programming. This is the book Mark Space recommends, especially to learn OO programming. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Greyed out stores probably do not have the item in stock. Try looking for it with a bookfinder. |
recommend book⇒Effective Java: second edition | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
by | Joshua J. Bloch | 978-0-321-35668-0 | paperback | |||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
birth | 1961-08-28 age:56 | 978-0-13-715002-1 | WebBook | |||||||||||||||||||||||||||||||||||||||||||||||||||||
publisher | Prentice Hall | B000WJOUPA | kindle | |||||||||||||||||||||||||||||||||||||||||||||||||||||
published | 2008-05-28 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
No design patterns, just generic advice on good Java programming style. This is considered the best explanation of generics, even though it has just one chapter on generics. People claim it all came clear after reading his explanation. It is also consider the best explanation of serialization. Not to be confused with his earlier Effective Java Programming Language Guide. book website | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Greyed out stores probably do not have the item in stock. Try looking for it with a bookfinder. |
recommend book⇒Java Generics and Collections | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
by | Maurice Naftalin & Philip Wadler | 978-0-596-52775-4 | paperback | |||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
publisher | O’Reilly | 978-0-596-55150-6 | eBook | |||||||||||||||||||||||||||||||||||||||||||||||||||||
published | 2006-10-18 | B0026OR2HM | kindle | |||||||||||||||||||||||||||||||||||||||||||||||||||||
Covers both generics and Collections. Covers Java 1.5+ features such as autoboxing, for:each as well. Recommended by Mike Schilling. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Greyed out stores probably do not have the item in stock. Try looking for it with a bookfinder. |
recommend book⇒Just Java 2, sixth edition | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
by | Peter van der Linden | 978-0-13-148211-1 | paperback | |||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
publisher | Prentice Hall | 978-0-13-700990-9 | eBook | |||||||||||||||||||||||||||||||||||||||||||||||||||||
published | 2004-07-01 | 978-0-13-493982-7 | audio | |||||||||||||||||||||||||||||||||||||||||||||||||||||
B001MDC0FW | kindle | |||||||||||||||||||||||||||||||||||||||||||||||||||||||
Covers Java 5 aka 1.5. Peter has a sense of humour and breaks the drudgery of reading with a funny story at the end of each chapter. He explains through simple examples. This is a book you can sit down and read and not fall asleep. I helped edit and proofread the chapters on enums and genericity. This is good introduction that won’t overwhelm you. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Greyed out stores probably do not have the item in stock. Try looking for it with a bookfinder. |
This page is posted |
http://mindprod.com/jgloss/generics.html | |
Optional Replicator mirror
|
J:\mindprod\jgloss\generics.html | |
Please read the feedback from other visitors,
or send your own feedback about the site. Contact Roedy. Please feel free to link to this page without explicit permission. | ||
Canadian
Mind
Products
IP:[65.110.21.43] Your face IP:[100.28.231.85] |
| |
Feedback |
You are visitor number | |