Restrictions and Limitations Core Java

In the following sections, we discuss a number of restrictions that you need to considerwhen working with Java generics. Most of these restrictions are a consequence of type erasure.

Type Parameters Cannot Be Instantiated with Primitive Types

You cannot substitute a primitive type for a type parameter. Thus, there is no Pair<double>, only Pair<Double>. The reason is, of course, type erasure. After erasure, the Pair class has fields of type Object, and you can’t use them to store double values. This is an annoyance, to be sure, but it is consistent with the separate status of primitive types in the Java language. It is not a fatal flaw—there are only eight primitive types, and you can always handle them with separate classes and methods when wrapper types are not an acceptable substitute.

Runtime Type Inquiry Only Works with Raw Types

Objects in the virtual machine always have a specific nongeneric type. Therefore, all type inquiries yield only the raw type. For example,

You Cannot Throw or Catch Instances of a Generic Class

You can neither throw nor catch objects of a generic class. In fact, it is not even legal for a generic class to extend Throwable. For example, the following definition will not compile:

However, it is ok to use type variables in exception specifications. The following method is legal:

Arrays of Parameterized Types Are Not Legal

You cannot declare arrays of parameterized types, such as

An array remembers its component type and throws an ArrayStoreException if you try to store an element of the wrong type:

But erasure renders this mechanism ineffective for generic types. The assignment

would pass the array store check but still result in a type error. For this reason, arrays of parameterized types are outlawed.

ArrayList<Pair<String>> is safe and effective.

You Cannot Instantiate Type Variables

You cannot use type variables in expression such as new T(...), new T[...], or T.class. For example, the following Pair<T> constructor is illegal:

Type erasure would change T to Object, and surely you don’t want to call new Object().

As a workaround, you can construct generic objects through reflection, by calling the Class. newInstance method. Unfortunately, the details are a bit complex. You cannot call

The expression T.class is not legal. Instead, you must design the API so that you are handed a Class object, like this:

This method could be called as follows:

Note that the Class class is itself generic. For example, String.class is an instance (indeed, the sole instance) of Class<String>. Therefore, the makePair method can infer the type of the pair that it is making. You cannot construct a generic array:

Type erasure would cause this method to always construct an array Object[2].

If the array is only used as a private instance field of a class, you can declare the array as Object[] and use casts when retrieving elements. For example, the ArrayList class could be implemented as follows:

Here, the cast E[] is an outright lie, but type erasure makes it undetectable. This technique does not work for our minmax method since we are returning a T[] array, and a runtime error results if we lie about its type. Suppose we implement public static <T extends Comparable>T[] minmax(T[] a)

compiles without any warning. A ClassCastException occurs when the Object[] reference is assigned to the String[] variable.

In this situation, you can use reflection and call Array.newInstance:

The toArray method of the ArrayList class is not so lucky. It needs to produce a T[] array, but it doesn’t have the component type. Therefore, there are two variants:

The second method receives an array parameter. If the array is large enough, it is used. Otherwise, a new array of sufficient size is created, using the component type of result.

Type Variables Are Not Valid in Static Contexts of Generic Classes

You cannot reference type variables in static fields or methods. For example, the following clever idea won’t work:

If this could be done, then a program could declare a Singleton<Random> to share a random number generator and a Singleton<JFileChooser> to share a file chooser dialog. But it can’t work. After type erasure there is only one Singleton class, and only one singleInstance field. For that reason, static fields and methods with type variables are simply outlawed.

Beware of Clashes After Erasure

It is illegal to create conditions that cause clashes when generic types are erased. Here is an example. Suppose we add an equals method to the Pair class, like this:

The remedy is, of course, to rename the offending method.The generics specification cites another rule: “To support translation by erasure, we impose the restriction that a class or type variable may not at the same time be a subtype of two interface types which are different parameterizations of the same interface.” For example, the following is illegal:

GregorianCalendar would then implement both Comparable<Calendar> and Comparable<Gregorian-Calendar>, which are different parameterizations of the same interface. It is not obvious what this restriction has to do with type erasure. After all, the nongenericversion

The reason is far more subtle. There would be a conflict with the synthesized bridge methods. A class that implements Comparable<X> gets a bridge method

You cannot have two such methods for different types X.

All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd Protection Status

Core Java Topics