• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Tim Cooke
  • Campbell Ritchie
  • Ron McLeod
  • Junilu Lacar
  • Liutauras Vilda
Sheriffs:
  • Paul Clapham
  • Jeanne Boyarsky
  • Henry Wong
Saloon Keepers:
  • Tim Moores
  • Tim Holloway
  • Stephan van Hulst
  • Piet Souris
  • Carey Brown
Bartenders:
  • Jesse Duncan
  • Frits Walraven
  • Mikalai Zaikin

Vararg Generic

 
Ranch Hand
Posts: 53
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I don't understand how array store check is false positive at (1a), how (5)'s compilation succeeds and why (6) gives ClassCastException?

 
Ranch Hand
Posts: 5575
Eclipse IDE Windows XP Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Jeet, Please use code tag while posting your code. it is hard to read your code!
 
Saloon Keeper
Posts: 13999
315
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Why would there be a compilation error at 5? stackOfStacks is a MyStack<MyStack<Integer>>, and intStack is a MyStack<Integer>. Popping an element from stackOfStacks into intStack makes perfect sense to the compiler.

It also works at runtime, because at runtime all the generic information is discarded, and all that the JVM sees is the following:
And this is perfectly valid! However, it gets a runtime exception at 6 because the JVM does the following:
This will throw a ClassCastException, because intStack.pop() will return a Double, not an Integer.
 
Jeet Jain
Ranch Hand
Posts: 53
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Firstly, I didn't get how (1a) is possible. T represents MyStack<Integer> so casting MyStack<Double> to MyStack<Integer> should not be allowed, right?

Secondly,(even if (1a) was allowed) after the call to asStackMalicious(), stackOfStacks holds a MyStack<Double> only. Popping this and assigning it to MyStack<Integer> intStack at (5) should not be allowed, right?

I am very confused when we should take erasure into account and when we should not.
 
Stephan van Hulst
Saloon Keeper
Posts: 13999
315
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Erasure happens just before runtime. So when the program runs, it has no access to generic type parameters.

It's not very hard once you get the hang of it. The compiler only checks statements one at a time.

1a) works, because casting is a runtime operation. It doesn't matter that you're casting a MyStack<Double> or any other type of MyStack, because you're casting it to the raw type without parameters. You are then left with a T and you're assigning it to a T[] as its first element. The compiler is happy, and it works at runtime because of type erasure.

5) works, because the compiler sees a MyStack<Integer>, and you're using the pop() method, which tells the compiler it will return a MyStack<Integer>, so the compiler is happy. The fact that it actually returns a MyStack<Double> is not visible to the compiler. At runtime it doesn't matter, because the parameters get erased anyway.

Finally, things go wrong at 6), because the JVM is casting (a runtime operation) an Object to an Integer. Why Object? Because of type erasure. At runtime, all collections return Object, and then cast them to the parameter type. So it's trying to cast an Object (specifically a Double) to an Integer, which obviously gives a ClassCastException.
 
Jeet Jain
Ranch Hand
Posts: 53
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
ohhh thank you so much:) i finally got it
 
Jeet Jain
Ranch Hand
Posts: 53
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
can you also explain me considering erasure in overriding?



Why does it give an error?

Compare it to this:

 
Jeet Jain
Ranch Hand
Posts: 53
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In the 2nd file it gives an error at (4) saying it wants M instead of N. When I make it M it gives error at (3) saying same erasure as (1). I'm confused.
 
Stephan van Hulst
Saloon Keeper
Posts: 13999
315
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
This code won't compile because the set() method in SubZ<E> does not override set() in SupZ, because SubZ<E>'s signature is set(E), and because you're extending the raw SupZ, the method it inherits is set(Object). So you're not overriding the method, but you're overloading it instead.

However, after erasure they have the same signature: set(Object). As you know, it's not allowed to overload a method with the same signature.

The same is true for the other pieces of code. You're extending a SupC<M>, so you can only override set(M). Instead, you're overloading with set(N), which is a different type, but they both have the same erasure: set(Object).
 
Greenhorn
Posts: 14
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jeet Jain wrote:In the 2nd file it gives an error at (4) saying it wants M instead of N. When I make it M it gives error at (3) saying same erasure as (1). I'm confused.



What I find particularly tricky are the get() in SubC1 and SubC2.

In SubC1 the get() as you note, will give a compiler error because the return type should be M and not N. When you change the return type to M the SubC1 correctly overrides the method in the parent class SupC and the compile error goes away.

In SubC2, though, you don't get the same compile error presumably because N extends M. This would seem to imply that the rule to override is somehow validated if the return type is a subclass of parent return type. But if you tried to cast M to N you would see that won't work.

So I am a bit lost as to why get() in SubC2 legally overrides the get() in SupC.
 
Stephan van Hulst
Saloon Keeper
Posts: 13999
315
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In Java, method parameters are invariant. This means that to override the method, its parameters must be of exactly the same type as declared in the superclass. If you use wider or narrower parameters, the method will be overloaded instead.

However, since Java 1.5, return types are covariant. This means that when you override a method, the return type may be narrower than in the superclass.

get() in SubC2<M, N extends M> is valid, because it adheres to both rules. It has the same method signature as get() in SupC<M>, and its return type is a subtype of the return type declared in the superclass.

set(N) however isn't valid, because method parameters are invariant, and N is not M. Instead, the method would be overloaded, but since the parameters are generic, they will be erased after compile time, leaving the class with two overloaded versions of set(Object), which is illegal.
 
Jeet Jain
Ranch Hand
Posts: 53
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:set(N) however isn't valid, because method parameters are invariant, and N is not M. Instead, the method would be overloaded, but since the parameters are generic, they will be erased after compile time, leaving the class with two overloaded versions of set(Object), which is illegal.



But then doesn't that mean that at compile time it seems like overloading but at runtime , after erasure, it has overriden it (not overloaded). Why is that wrong?
 
Jeet Jain
Ranch Hand
Posts: 53
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Also, how come the 1st time the compiler allowed (3) and gave error at (4) but when the error at (4) was cured by changing N to M it gave error at (3)? Why didnt it give an error the 1st time?
 
Stephan van Hulst
Saloon Keeper
Posts: 13999
315
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Jeet Jain wrote:But then doesn't that mean that at compile time it seems like overloading but at runtime , after erasure, it has overriden it (not overloaded). Why is that wrong?


Because which method is called is determined at compile time. Java is a static language.

Also, how come the 1st time the compiler allowed (3) and gave error at (4) but when the error at (4) was cured by changing N to M it gave error at (3)? Why didnt it give an error the 1st time?


It may depend on your compiler. Sometimes they deal with one error at a time. There's nothing you can say about the correctness until it compiles completely without any errors.
 
Jeet Jain
Ranch Hand
Posts: 53
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
But remember you meant that the compiler sees generic and only JVM sees the erasure done before runtime. Then why does compiler complain about the erasures of set(Object) being the same? It doesnt see erasure right?
 
Stephan van Hulst
Saloon Keeper
Posts: 13999
315
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Okay, what if you had a SubC2<Number, Integer>? The compiler would determine that it inherits the method set(Number) from SupC<Number>, and it also has an overloaded version set(Integer).

Now, if we called the set method using a Double, the compiler would determine that the set(Number) method should be called, because set(Integer) doesn't fit.

However, if after erasure the runtime system would override the first set(Object) (the Number version) with the second set(Object) (the Integer version), it would be calling a method designed for Integer, on a Double!

That's why you can not overload methods if they have the same erasure.
 
Jeet Jain
Ranch Hand
Posts: 53
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You mean that at compile time set(Number) of SupC is called but after erasure compiler chooses to call set(Integer), i.e set(Object), instead? And that gives an error?
 
Stephan van Hulst
Saloon Keeper
Posts: 13999
315
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, that's not how it works, I was showing you what would go wrong if the language worked the way you proposed.

Let's keep things clear:

- Methods can be overridden by a subclass using the exact same signature, and the same or narrower return type.
- Methods can be overloaded by the same class or a subclass using a signature with the same name, but different parameter types. This includes parameters that are strict super- or subtypes of the parameters of the overloaded method. Overloading with generic parameters is possible, so long as they do not have the same erasure. The following is legal:

Here, the erasure of T is Object. The erasure of U is String, so the two methods successfully overload each other.
 
Jeet Jain
Ranch Hand
Posts: 53
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
wow! thanks so much. I finally got the rules even though I'm confused about the reason behind the rules. But its fine for now. I have my OCJP exam tomorrow. Any tips? Anything about formats and all?
 
Ranch Hand
Posts: 50
Android Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
What I don't understand is how #4 compiles:


Given that the method signature is

How can you pass a custom generic class as a varargs array?

EDIT:
Now I understand, it is because T in this case was MyStack<Integer>.
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic