Welcome Message

Hi, welcome to my website. This is a place where you can get all the questions, puzzles, algorithms asked in interviews and their solutions. Feel free to contact me if you have any queries / suggestions and please leave your valuable comments.. Thanks for visiting -Pragya.

Showing posts with label Generics. Show all posts
Showing posts with label Generics. Show all posts

July 8, 2010

Generics and Unboxing

When using legacy (non-type safe) collections—watch out for unboxing problems! If you declare a non-generic collection, the get() methodALWAYS returns a reference of type java.lang.Object. Remember that unboxing can't convert a plain old Object to a primitive, even if that Object reference points to an Integer (or some other primitive) on the heap. Unboxing converts only from a wrapper class reference (like an Integer or a Long) to a primitive.

Generics exist only till compile time. They do not exist at run time

All your generic code is strictly for the compiler. Through a process called "type erasure," the compiler does all of its verifications on your generic code and then strips the type information out of the class bytecode. At runtime, ALL collection code—both legacy and new Java 5 code you write using generics—looks exactly like the pre-generic version of collections. None of your typing information exists at runtime. In other words, even though you WROTE

List myList = new ArrayList();


By the time the compiler is done with it, the JVM sees what it always saw before Java 5 and generics:

List myList = new ArrayList();

The compiler even inserts the casts for you—the casts you had to do to get things out of a pre-Java 5 collection.

Think of generics as strictly a compile-time protection. The compiler uses generic type information (the in the angle brackets) to make sure that your code doesn't put the wrong things into a collection, and that you do not assign what you get from a collection to the wrong reference type. But NONE of this protection exists at runtime.


This compiler warning isn't very descriptive, but the second note suggests that you recompile with -xlint:unchecked. If you do, you'll get something like this:

javac -Xlint:unchecked TestBadLegacy.java
TestBadLegacy.java:17: warning: [unchecked] unchecked call to
add(E) as a member of the raw type java.util.List
list.add(new String("42"));
^
1 warning

When you compile with the -Xlint:unchecked flag, the compiler shows you exactly which method(s) might be doing something dangerous.

January 18, 2010

Creating Generic Methods

Imagine you want to create a method that takes an instance of any type, instantiates an ArrayList of that type, and adds the instance to the ArrayList. The class itself doesn't need to be generic; basically we just want a utility method that we can pass a type to and that can use that type to construct a type safe collection. Using a generic method, we can declare the method without a specific type and then get the type information based on the type of the object passed to the method. For example:

import java.uti1.*;
public class CreateAnArrayList {
public < t > void makeArrayList(T t) { // take an object of an
// unknown type and use a
// "T" to represent the type
List< t > list = new ArrayList(); // now we can create the
// list using "T"
list.add(t);
}
}

In the preceding code, if you invoke the makeArrayList() method with a Dog instance, the method will behave as though it looked like this all along:

public void makeArrayList(Dog t) {
List list = new ArrayList();
list.add(t);
}


And of course if you invoke the method with an Integer, then the T is replaced by Integer (not in the bytecode, remember—we're describing how it appears to behave, not how it actually gets it done).

The strangest thing about generic methods is that you must declare the type variable BEFORE the return type of the method:

public void makeArrayList(T t)

The before void simply defines what T is before you use it as a type in the argument. You MUST declare the type like that unless the type is specified for the class. In CreateAnArrayList, the class is not generic, so there's no type parameter placeholder we can use.

You're also free to put boundaries on the type you declare, for example if you want to restrict the makeArrayList() method to only Number or its subtypes (Integer, Float, and so on) you would say

public void makeArrayList(T t)

More on Generics

look at the following statements and figure out which will compile:


1) List list = new ArrayList<dog>();
2) List aList = new ArrayList<dog>();
3) List foo = new ArrayList();
4) List cList = new ArrayList<integer>();
5) List bList = new ArrayList<animal>();
6) List dList = new ArrayList<dog>();

The correct answers (the statements that compile) are 1, 2, and 5. The three that won't compile are

Statement: List foo = new ArrayList();

Problem: you cannot use wildcard notation in the object creation. So the new ArrayList() will not compile.

Statement: List cList = new ArrayList();

Problem: You cannot assign an Integer list to a reference that takes only a Dog (including any subtypes of Dog, of course).

Statement: List dList = new ArrayList();

Problem: You cannot assign a Dog to . The Dog is too "low" in the class hierarchy. Only or < Object > would have been legal.

Generics Reloaded

Generic collections give you the same benefits of type safety that you've always had with arrays, but there are some crucial differences that can bite you if you aren't prepared. Most of these have to do with polymorphism.

You've already seen that polymorphism applies to the "base" type of the collection:

List myList = new ArrayList();

In other words, we were able to assign an ArrayList to a List reference, because List is a supertype of ArrayList. Nothing special there—this polymorphic assignment works the way it always works in Java, regardless of the generic typing.

But what about this?

class Parent { }
class Child extends Parent { }
List myList = new ArrayList();

Think about it for a minute.
Keep thinking…

No, it doesn't work. There's a very simple rule here—the type of the variable declaration must match the type you pass to the actual object type. If you declare List foo then whatever you assign to the foo reference MUST be of the generic type . Not a subtype of . Not a supertype of .Just .

These are wrong:

List< Object > myList = new ArrayList(); // NO!
List numbers = new ArrayList(); // NO!
// remember that Integer is a subtype of Number

But these are fine:

List myList = new ArrayList(); // yes
List myList = new ArrayList(); // yes