2

What wrong in this method declaration?

public abstract class A<K extends Number>{  
   public abstract <K> A<K> useMe (A<K> k);
}

I see compile error:

java: type argument K is not within bounds of type-variable K

my first thought for this compile error was that as - It is not guaranteed that K is Number in my method declaration, that's why issue is coming.

But in another case as below:

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

A<? super K> is again not guaranteed that it is Number (However IDE sign warning) but it is not compile error.

What are the differences?

gstackoverflow
  • 36,709
  • 117
  • 359
  • 710
  • This is rather surprising for me too. I would expect that signature to fail. Just for information, if I change `A super K>` to `A super Object>`, where `Object` is the erasure of `K` there, then it fails to compile. Looking for some answer that explains it well. – Rohit Jain Mar 09 '14 at 08:49
  • But my IDE say that it is compile error, but after manual comple I don't see compile errors – gstackoverflow Mar 09 '14 at 08:55
  • @RohitJain which compiler are you using? `A super Object>` as an argument type is compiling fine for me with both the javac and Eclipse compilers with source levels 1.7 and 1.8. – Erwin Bolwidt Mar 09 '14 at 09:17
  • @ErwinBolwidt Doesn't work for me under JDK 1.8.0 - build 129. And neither in eclipse with source levels at 1.8 – Rohit Jain Mar 09 '14 at 09:20
  • Ah I tried to many options and didn't see that you used super instead of extends. Try `super Double` or `extends Object` like in the answer below (not `super Object`). When ? is involved, things don't work the same. But try to make an invocation of the method useMe in which you would invoke it with A - there's no way in which you can write that directly or indirectly. – Erwin Bolwidt Mar 09 '14 at 09:24
  • Well, I was talking about using `A super Object>` instead of `A super K>` as in question. Later one compiles, but former doesn't. :( – Rohit Jain Mar 09 '14 at 09:27
  • java version "1.7.0_45" I see behaviour according Rohit Jain explanation – gstackoverflow Mar 09 '14 at 09:29
  • `A super K>` where `class A` but to `A super Number>`. You can verify this using a test method `public void test(A> a) { A b = null; a.useMe(b); }`, which is valid, but if you declare b as `A` it doesn't compile. – Erwin Bolwidt Mar 09 '14 at 09:38
  • @ErwinBolwidt The `K` used there is a different type parameter, that has no bounds. So, it's erasure would be `Object`. – Rohit Jain Mar 09 '14 at 09:40
  • @RohitJain I don't think erase applies here, at least not as you say it. Erasure gets rid of all the generics, so the erasure is `A`, not `A super Object>` – Erwin Bolwidt Mar 09 '14 at 09:44
  • @ErwinBolwidt Yeah I know that. I was just thinking that, since the bounds to `K` is just `Object`, I assumed `A super Object>` should also work, instead of `A super K>`. But I think I was wrong. I'm getting close to the answer, and will post it soon. – Rohit Jain Mar 09 '14 at 09:52
  • @ErwinBolwidt gstackoverflow. Added an answer. Hope that will clear it. – Rohit Jain Mar 09 '14 at 10:21
  • @Rohit Jain I try to digest it – gstackoverflow Mar 09 '14 at 10:34
  • 2
    @gstackoverflow Seems like my derivation of concept was a bit wrong. Here's the [same question posted on SO](http://stackoverflow.com/questions/20752781/lower-bounded-wildcard-not-checked-against-upper-bounded-type-parameter?rq=1), where it's mentioned that perhaps Java doesn't do bound check with lower bounded wildcard. You might want to have a look. – Rohit Jain Mar 09 '14 at 14:44
  • Thanks, I will make it. – gstackoverflow Mar 09 '14 at 19:51
  • @Rohit Jain I frustrated when users see problem with generic advise to research erasure mindless. I see that generic in java created so bad that people with huge experience (as Rohit Jain ) cannot understand generic construction exact. it is upseted for me. – gstackoverflow Mar 09 '14 at 19:59

2 Answers2

1

remove extends Number from class and add it with method i.e. public abstract class A<T>{ public abstract <T extends Number> A<T> useMe(A<T> t); }

Karsan
  • 269
  • 3
  • 14
0

Ok, here's a different answer. The reason is that though you use <K> as a generic in your method, it has nothing to do with the <K> you used in your class. It would be more obvious if you wrote

abstract class A<K extends Number>{
    public abstract <T> A<T> useMe(A<T> t);
}

Here <T> is some generic, but you have limited A to only use generics which extend Number and <T> in this case doesn't and it fails to implement the contract of A. Here is where the error comes from. For that reason you should write

abstract class A<K extends Number>{
    public abstract <T extends Number> A<T> useMe(A<T> k);
}
svz
  • 4,516
  • 11
  • 40
  • 66
  • No, I want to understand cause of problem. I just investigate generics – gstackoverflow Mar 09 '14 at 08:29
  • @gstackoverflow, gave a different answer – svz Mar 09 '14 at 08:36
  • I don't understand why **public abstract A extends Number> useMe (A super K> k);** is valid at this case ? – gstackoverflow Mar 09 '14 at 08:40
  • @svz is correct. Your declaration of type variable in the method is shadowing the declaration in the class, which is hidden because of this. So you're now saying that your method can return any A without restricting T to a subclass of Number - but that is incompatible with the way in which class A is declared, which does require it to be a subclass of Number. – Erwin Bolwidt Mar 09 '14 at 08:42
  • 1
    You are completely missing the question. OP understand why the first case fails to compile. What he's asking is, why the second case compiles fine? Which is rather surprising for me too. – Rohit Jain Mar 09 '14 at 08:47
  • 1
    @ErwinBolwidt Where do you see in the answer an explanation for the second case - `public abstract A extends Number> useMe (A super K> k);`? – Rohit Jain Mar 09 '14 at 08:50
  • @RohitJain Sorry, you're right. The local shadowing of is a bit of a red herring in the question, it has nothing to do with the problem. `useMe(A extends Object> k)`, `useMe(A super Double> k)` and `useMe(A> k)` are all valid ways to declare the method and the compiler restricts these automatically to subclasses of `Number`. Can't quickly find where this is in the JLS though. – Erwin Bolwidt Mar 09 '14 at 09:11
  • @ErwinBolwidt I don't understand how `? super Object` would work. I wouldn't expect it to, and neither it compiles. If this works, that would mean, we can give higher bounds to the type argument, than what is specified in type parameter. So, why would just giving `A` won't work. – Rohit Jain Mar 09 '14 at 09:26