aspose file tools*
The moose likes Programmer Certification (SCJP/OCPJP) and the fly likes Generics question (Devaka Diagnostic Exam, Question 57) Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Certification » Programmer Certification (SCJP/OCPJP)
Bookmark "Generics question (Devaka Diagnostic Exam, Question 57)" Watch "Generics question (Devaka Diagnostic Exam, Question 57)" New topic
Author

Generics question (Devaka Diagnostic Exam, Question 57)

Ruben Soto
Ranch Hand

Joined: Dec 16, 2008
Posts: 1032
Given this code:

You can legally insert this at //1:


But not this:


I understand the rationale for the second method not being legal (since the K parameter in this method is unbounded, and so A<K> is not within bounds.) The question is: why is the first method legal? My guess is that the compiler gives wildcards more freedom when satisfying bounds, and as long as there is some value of K for which A<? super K> satisfies the bound where the type of A must extend Number (given by the generic class declaration) the compiler will allow it. Could someone clarify?

Thanks,

Ruben

All code in my posts, unless a source is explicitly mentioned, is my own.
Marco Reuel Perez
Ranch Hand

Joined: Apr 16, 2009
Posts: 45
Second code does not work. That's because the "K" in the method declaration is hiding the "K" in the class declaration. If you have removed the additional "K" declaration in the method, i.e :


The K in the method declaration hides the K in the class declaration and they both are unrelated. Now, when you re-declare K and then use it with class A, there is no guarantee that it is going to be in the bounds of class A's K, i.e, there is no guarantee that the K in the method extends Number.

-Reuel


SCJP 6 - 91%
<><
Ruben Soto
Ranch Hand

Joined: Dec 16, 2008
Posts: 1032
Thanks for your answer, Marco. I agree with you that in theory that method shouldn't be legal. But, as per Devaka's solution, it is (try to run it through the javac compiler.)

These methods are both legal:



Hopefully someone can explain this.
Ruben Soto
Ranch Hand

Joined: Dec 16, 2008
Posts: 1032
For the record, I am leaning towards this explanation: When the compiler encounters a wildcard it doesn't enforce bounds the way it does when it has a simple generic type parameter. In the case of the wildcard the compiler is satisfied with checking that an instantiation of the generic type (and an assignment to the generic type reference using the wildcard) is possible which will not break the bounds established elsewhere. I just need a more authoritative explanation.
Marco Reuel Perez
Ranch Hand

Joined: Apr 16, 2009
Posts: 45
You are right Ruben.

When I used javac it (first abstract method in your question) worked (to my surprise). I wonder what's happening too.. When I tried in eclipse it didn't allow me as expected. But javac allows.. Strange..

Now if I modify one of the abstract methods as follows, it wouldn't work..


Interesting find Ruben. I look forward for more substantiating explanation as well.. I don't know if I am missing something here.

-Reuel
Ruben Soto
Ranch Hand

Joined: Dec 16, 2008
Posts: 1032
Thanks for checking on this, Marco. The method that you show is actually instantiating an A<K> where K is not bounded. My working hypothesis is that when you have a wildcard as opposed to a type parameter the compiler allows it as long as it could possibly work in some cases.

Interesting that it doesn't work in Eclipse. I wonder if this is just a compiler-specific thing. It is very misleading though, since common sense says that it shouldn't work, yet it does (in javac, anyway.)
Ankit Garg
Sheriff

Joined: Aug 03, 2008
Posts: 9305
    
  17

Well lets go at this in a practical way. Lets take the first method



First of all, here K has nothing to do with K in the class declaration. You can even use this



Now the return type will work that's for sure as A is declared to be a sub-type of Number and so does the return type declares. As far as the parameter goes, the compiler allows A<? super D> as it knows that D will have to resolve to a sub-type of Number (or Number itself). Otherwise the calling code won't compile. Let's take an example



So basically I fell that the compiler here knows that the wildcards won't hurt the code as the calling code has gotta be legal. And if the calling code would be legal, then the declaration



Won't create any problems. The same is the case with the other example



Here again, the return type says A<? super Number> but the compiler knows that the class A won't allow anything like this to be returned



So the compiler knows that the returned object would be A<Number>. Similarly, in the parameter, the compiler knows that D will have to resolve to Number or a sub-type of Number. So there is nothing to worry there too...


SCJP 6 | SCWCD 5 | Javaranch SCJP FAQ | SCWCD Links
Ruben Soto
Ranch Hand

Joined: Dec 16, 2008
Posts: 1032
Great explanation, Ankit!

So basically when the compiler sees a wildcard it will leave the checking of bounds to code which actually instantiates the generic class.

To make sure I understand things, let's consider the method:



In this case, it's clear why the return A<K> makes this method illegal, since you could return A<K> from an actual implementation of this method, and the compiler can't check that K is within bounds. But even this method is illegal:



In this case, the compiler is preventing you from declaring an A<K> reference where K is out of bounds. You could argue that the compiler could actually let this code be legal, and check on the bounds when an instance of A is instantiated, but this is not the actual problem in this case. The actual problem is that now k is a reference of A which might be out of bounds, and you might be able to add to an actual A instance (which will be within bounds) passed as a parameter to the method an element of type K, which will break the type safety of the collection (since K is out of bounds.) This couldn't happen when the parameter had a wildcard, since you can't add elements through generic references with wildcards.

Let me know if you see any flaw in my reasoning, Ankit. And again, thanks for the great explanation.
Ankit Garg
Sheriff

Joined: Aug 03, 2008
Posts: 9305
    
  17

Well Ruben you are right. When you use an identifier for the generic type, then it can resolve to anything which might be out of the bounds for the type. Lets take our own code with some changes



Now here T will resolve to Object. So this breaks the bounds for GenericExp<K extends Number>. But with wildcard, this cannot happen as we cannot use the syntax that we used in this method call to decide what the wildcard resolves to. So modifying this code will work

reji singh
Ranch Hand

Joined: Apr 06, 2009
Posts: 52
Guys,

excellent stuff on Generics. Everytime i see questions on Generics with little play on them, I see things getting more complicated. Wonder when will i master this topic

But you guys are simply great with ideas.
Clay Chow
Ranch Hand

Joined: Nov 09, 2008
Posts: 35
Ruben Soto wrote:\


In this case, the compiler is preventing you from declaring an A<K> reference where K is out of bounds. You could argue that the compiler could actually let this code be legal, and check on the bounds when an instance of A is instantiated, but this is not the actual problem in this case. The actual problem is that now k is a reference of A which might be out of bounds, and you might be able to add to an actual A instance (which will be within bounds) passed as a parameter to the method an element of type K, which will break the type safety of the collection (since K is out of bounds.) This couldn't happen when the parameter had a wildcard, since you can't add elements through generic references with wildcards.

Let me know if you see any flaw in my reasoning, Ankit. And again, thanks for the great explanation.


I think I am following. I agree with why/why not the return type generics compile/do not compile. But have a question with the parameter ones.


So you are saying:

(1) public abstract <K> A<? extends Number> useMe(A< ? super K> k);

(2) public abstract <K> A<K> useMe(A<K> k);

(3) public abstract <K> A<? super Number> useMe(A< ? extends K> k);


One question:
For (3), the parameter generic does compile because you are unable to add to the parameter collection. (2) would not compile because one would be able to add to the collection. However, (1) compiles, and you can still add to the parameter collection (because a collection reference with generic super, allows additions, sometimes though). So maybe this still enforces the class generic declaration.

Also, in this example, 'A' is not a collection, but just another Object that doesn't do much. However, if A was a collection (say it did extend ArrayList), you would still be able to add to the parameter collection in (1).


Another question:
It was said that the parameter generics in (1) and (3) are valid because the type parameter <K extends Number> would be checked when the 'A' is instantiated.
Could this not also apply to the parameter generic in (2) ? Since the A<K> would be instantiated (and therefore be valid) before it is passed into the method, it stands to reason that K must therefore follow <K extends Number> and would therefore be valid to add elements of type K into that collection.
shweta jha
Greenhorn

Joined: May 12, 2009
Posts: 3
thanks ankit for help


dialog marketing
san marcos tx apartments
Ruben Soto
Ranch Hand

Joined: Dec 16, 2008
Posts: 1032
Clay,

You make some very good points. I was trying to make sense of this, and hadn't thought about the A<? super K> argument, only about the A<? extends K>. I think the compiler allows an explicit type when the type can be verified to be in bounds, but it allows a declaration in wildcard when the wildcard could resolve at least in some cases to a type which will be in bounds. The question that you put is valid though.
Anatole Dominguez
Greenhorn

Joined: May 12, 2010
Posts: 2
When I try to compile this line



with Eclipse, does not compile

but, if I use Javac in the same file in Windows Console it does compile

Can someone explain that to me??
Ankit Garg
Sheriff

Joined: Aug 03, 2008
Posts: 9305
    
  17

Anatole, for the purpose of SCJP, always compile and run your program from the command line using the JDK javac and java commands. IDEs like Eclipse and Netbeans sometimes behave differently than the JDK compiler but the SCJP exam is based on the JDK compiler. So for the exam you should rely on the behavior of the JDK compiler...
 
 
subject: Generics question (Devaka Diagnostic Exam, Question 57)