Consider the following code :

class R2<E>
{
	E a;
	E get()
	{
		return a;
	}
	void set(E a)
	{
		this.a=a;
	}
	public static void main(String aa[])
	{
		R2 nn1=new R2<Integer>();
		nn1.set("hello");           (1)
		//String r=nn1.get();
		//Integer t=nn1.get();
	}
}

In line (1), an unchecked warning is given as the compiler is not sure as to the generic type of nn1 (its raw type). But what I can't understand is that when the program is run, why is no exception thrown at line (1).

What is E once the program has been compiled ?

Recommended Answers

All 7 Replies

That's really interesting. I too can assign a String too what should be an Integer and it works.
The real answer is to declare nn1 fully, as in
R2<Integer> nn1 = new R2<Integer>();
ij which case the compiler correctly rejects (1)

That is an interesting question. Have tried this:

class R2<E>
{
	E a;
	E get()
	{
		return a;
	}
	void set(E a)
	{
		this.a=a;
	}

        void print() {
            System.out.println(a.getClass());
        }

	public static void main(String aa[])
	{
		R2 nn1=new R2<Integer>();

                nn1.print();
	}
}

Can you tell us if it works and what it prints?

I tried the code (I added

nn1.set("Hello")

before nn1.print(), otherwise NullPointException was thrown). The result was : class java.lang.String.

Also, if we add

String bb=nn1.get();

, it gives compile time error, Incompatible Types : String and Object

What is E once the program has been compiled ?

There is no type "E" after the class has been compiled. Generics in Java are based on type erasure and are compile time constructs i.e. your code is as safe as you want it to be. Deep down inside, all your "generic" variables are converted to Object types, unless you have a "bound" placed on your types in which case the variable becomes the erasure of that upper bound. This is one of the reasons why type declarations at the class level don't allow "super".

This is the reason why `nn1.set("Hello")` works while `String bb = nn1.get()` doesn't; a String is an object but an Object need not always be a String.

Another interesting thing to note is that the "E" needs to be stored somewhere since there are some reflection based methods added to the reflect package which deal with generics. (e.g. Field method getGenericType()). This is done by updating the class file format for Java 5+ and adding a new attribute "Signature" which stores this "generic" information present at the source level for querying purposes.

class Mine<T> {
    
    private T var;
    
    public Mine(T var) {
        this.var = var;
    }
    
    public void printInfo() {
        try {
            Field f = this.getClass().getDeclaredField("var");
            System.out.println(f.getGenericType());
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }
    
}

Thanks. I understand that if a "bound" is placed, i.e. it has been parameterized, like

Mine<Integer> ob

, then, at runtime, the generic variables are converted to Integer type. On the other hand, in

Mine ob

, the generic variables are replaced by Object. Right ?

In the line :

Mine <Integer> ob=new Mine();

, any operation on ob strictly follows the parameterized paradigm, i.e. we can't send a String, for example in a method that accepts the generic parameter. On the contrary, statements like

Mine ob=new Mine<Integer>()

doesn't follow the parameterized paradigm strictly, i.e you can even pass String to a similar method. Does this mean that whether the parameterized paradigm is followed strictly or not, depends upon the LHS of the reference assignment statement. Is this right ?

then, at runtime, the generic variables are converted to Integer type. On the other hand, in

Nope; nothing is done at *runtime*. The 'T' in Mine assumes the type of the bound specified when giving the type parameter at class level. If no restriction is specified, Object is used.

Does this mean that whether the parameterized paradigm is followed strictly or not, depends upon the LHS of the reference assignment statement. Is this right ?

Yes; it is the declaration which matters since checks are done at compile time and not runtime but mixing things is never recommended (leaving out the type information in RHS) and the aim should always be to have a codebase with very few if not zero generics related warnings.

Thanks a lot.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.