Everything about Generics

 - Why good? Why? What is it with this brackets inside java code?
 - It's for you my son to be advise sooner when you wrong.

 1. Generics Introduction
 2. Raw Types
 3. Generics, Inheritance, and Subtypes
 4. Generics Wildcards
 5. Wildcards and Subtyping
 6. Bounded type parameters
 7. Type Inference
 8. The Get and Put Principle or the PECS Rule and My Super Rule


Generics Introduction


Generics was introduced once with release of java 1.5. The scope of generics is to detect errors at compile time.
And that's it. Go further!!

you may also want to know:
Definition. A generic type is a generic class or interface that is parametrized over types.

Conventions. The most commonly used type parameter names are:

•E - Element (used extensively by the Java Collections Framework)
•K - Key
•N - Number
•T - Type
•V - Value
•S,U,V etc. - 2nd, 3rd, 4th types

When we replace T with String for example, we will call this type argument

Syntax. A generic class is defined:

 class name{ ... }

And an simple example for defining:

public class Vehicle {
    private Object myObject;

    public void setMyObject(Object object) { this.object = object; }
    public Object getMyObject() { return object; }
}

public class Vehicle<T>  {
    // T stands for "Type"
    private T myType;

    public void setMyType(T myType) { this.myType = myType; }
    public T getMyType() { return myType; }
}

Invoking and Instantiating example:

To reference the generic Vehicle class, you must perform a generic type invocation, which replaces T with some concrete value, such as String :

Vehicle<String> vehicleWithBrand = new Vehicle<String>();
vehicleWithBrand.setMyType("Volvo");
vehicleWithBrand.setMyType(2015); //compiler error;
Vehicle<Integer>vehicleWithYear = new Vehicle<Integer>();
vehicleWithYear.setMyType("Volvo"); //compiler error;
vehicleWithYear.setMyType(2015);

Nice. All ocurence of Object was replaced with T. A type variable can be any non-primitive type you specify: any class type, any interface type, any array type, or even another type variable.

So what is happening??
We have a Vehicle and I can declare my Vehicle with a specific object.Wow nice.

We can declare a List with a generic type and if someone wants to put something bad in my list I will now. Well, you have all the time because generics are most used with Collections.

java 1.7 introduced the diamond.

Vehicle vehicleWithBrand = new Vehicle<>();

If the compiler can determine, or infer, the type arguments from the context we can use the diamond syntax.

Type erasure
All informations declared inside brackets are just for the compiler, at runtime any informations declared inside brackets will be deleted.To implement generics, the Java compiler applies type erasure to:

•Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
•Insert type casts if necessary to preserve type safety.
•Generate bridge methods to preserve polymorphism in extended generic types.

Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.

Raw Types

If we instantiate a vehicle without giving any type argument we have a raw type

Vehicle vehicleRawTypeVar = new Vehicle();

instantiating a parametrized type of Vehicle<T> simply requires to deliver an actual type argument.

Vehicle<String> vehicle = new Vehicle<String>();

So, what happens when you mix legacy code (previous to jdk1.5) with generig code? Then the compiler will raise a warning message similar with:

Note: Example.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

In our example we will get a this message if we use something like this:

vehicleRawTypeVar.setMyType(new Object() );

The compiler does not have enough type information to perform all type checks necessary to ensure type safety that is what the term "unchecked" means. The "unchecked" warning is disabled, by default, though the compiler gives a hint. To see all "unchecked" warnings, recompile with -Xlint:unchecked.

Don't worry to much, most of the development environments use it for compiling your code as default.


Generics, Inheritance, and Subtypes


You should already know what subtypes is and what means in object-oriented terminology,  "IS-A" relationship.

Let's declare some variables:

Vehicle<Number> vNum;
Vehicle<Integer> vInt;
Vehicle<Double> vdou;

Vehicle<Integer> and Vehicle<Number> doesn't have a "IS A" relationship. even if Integer extends Number.

Now lets declare something else:

List<String> list;
ArrayList<String> alist;

We can say now that ArrayList<String> IS-A List<String> 

Generics Wildcards


  Unknown type is represented by the wildcard ? - question mark. The wildcard can be used in a variety of situations: as the type of a parameter, field, or local variable; sometimes as a return type (though it is better programming practice to be more specific). The wildcard is never used as a type argument for a generic method invocation, a generic class instance creation, or a supertype.
  Wildcards comes in 4 flawors:
    1. upper bounded wildcards <? extends MyObject>
  In a variable declared with upper bounded wildcards you can only access the objecs. You can access objects inside as MyObject. And that is all you need to know. Just have in mind the folowing example:


public static void process(List<? extends MyObject> list) {
    for (MyObject elem: list) {}
}
You can use an upper bounded wildcard to relax the restrictions on a variable.
    2. unbounded wilcards <?>
  This is used when your implementation is using Object class functionality or when the code is using methods in the generic class that don't depend on the type parameter. 
  For any concrete type A, List<A> is a subtype of List<?>.
  It's important to note that List<Object> and List<?> are not the same. You can insert an Object, or any subtype of Object, into a List<Object>. But you can only insert null into a List<?>. 
    3. lower bounded wildcards <? super SomeObject>
lower bounded wildcard restricts the unknown type to be a specific type or a super type of that type.
have in mind the folowing example:


public static void addIntegers(List<? super Integer> list) {
    for (int i = 1; i <= 10; i++) {
        list.add(i);
    }
}
    4. wildcard capture
  In some cases, the compiler infers the type of a wildcard.   For example, a list may be defined as     List<?> but, when evaluating an expression, the compiler infers a particular type from the code. This scenario is known as wildcard capture.
  Look over type inference for more.

Wildcards and Subtyping


In order to understand better wilcards and subtyping I will provide 2 images to keep in your mind:

Bounded type parameters


Suppose we have a normal class, without any generic type. We can declare bounded type parameters only for methods. For example, a method that operates on numbers wants to accept only instances of Number or its subclasses.

public <N extends Number> Integer print(N n, ){
  System.out.println("N: " + u.getClass().getName() );
}

Bounded type parameters are key to the implementation of generic algorithms.

Multiple Bounds A type parameter can have multiple bounds for example:

Class A { /* ... */ }
interface B { /* ... */ }
interface C { /* ... */ }

class D <T extends A & B & C> { /* ... */ }
Class A must be specified first, else you get a compile-time error:

Type Inference


Definition: Type inference is a Java compiler's ability to look at each method invocation and corresponding declaration to determine the type argument (or arguments) that make the invocation applicable. The inference algorithm determines the types of the arguments and, if available, the type that the result is being assigned, or returned. Finally, the inference algorithm tries to find the most specific type that works with all of the arguments.

To illustrate this last point, in the following example, inference determines that the second argument being passed to the pick method is of type Serializable:

static <T> T pick(T a1, T a2) { return a2; }
Serializable s = pick("d", new ArrayList<String>());

The Get and Put Principle or the PECS Rule and My Super Rule



Some simple rule defined by Maurice Naftalin  in his Java Generics and Collections also known as The Get and Put Principle
  • Use the ? extends wildcard if you need to retrieve object from a data structure
  • Use the ? super wildcard if you need to put objects in a data structure
  • If you need to do both things, don’t use any wildcard.
PECS comes from “Producer Extends, Consumer Super” and is probably easier to remember and is a mnemonic developed by Joshua Bloch.

But now, My Super Rule, when you have ? super you say: Suuuper we can put something here! and the rest comes naturally.


Read the next page with the Restrictions on Generics.


Questions?? ...Comments, suggestions or any  Remarks?
Thanks for reading!!

No comments:

Post a Comment