A generic class' actual type argument is determined the moment you create an instance of it. You should be familiar with the following syntax:
If a method declares its own generic type parameters, the actual type argument of the parameter will be determined at the time you call the method.
Here T is determined separately for each method call. We call identity() using a
String literal, so the return type of the method will also be a String. This is called type inference. The compiler determines what T stands for based on the way you call the method. Compare:
The compiler infers from the formal type of the argument you're passing (Object) that T should be Object. So the method will return an Object. The compiler complains, because you're trying to assign an Object reference to a String variable.
Now, type bounds make things a little bit more interesting. When you have a formal type parameter, you can specify additional restrictions that the actual type argument has to adhere to.
Let's say you have the following method:
You now no longer call identify() on arguments of the Object or String type, because whatever the argument is, it has to be at least a Number:
When you call a generic method, you can even explicitly state what the type argument is, regardless of the type of the arguments you pass:
In this example, even though the argument type is Integer, we have explicitly stated that the type argument should be a Number.
Now, the example you have given makes things a little bit more confusing. The problem is that the class declares a type parameter K, but the individual methods also declare their own type parameters K. It's important to note that these are two completely different type parameters! The method's version of K 'hides' the class' version of K. Just to make it more easy for yourself, rename the class' version to M.
Now, how should you read a method declaration such as:
Here's what it says: useMe expects one argument of type ABS<foo>, where foo is something... anything... that happens to extend K. The method will then return an ABS<bar>, where bar can be something... anything... that happens to be a supertype of Number. Intuitively, this method will always return either an ABS<Number> or an ABS<Object>, but you won't know which of the two.
So what is K then? Like I explained earlier, if you don't state it explicitly, the compiler will infer K as the formal type of the argument you pass to it. If you pass an ABS<Double> then K will be Double.
Maybe you will start to see why 2. 3. and 4. shouldn't compile. None of the methods puts a bound on what K can be. So K could theoretically be an Object, or a String, or a Dog, or a House. This means that methods 2. 3. and 4. would theoretically accept an argument of the type ABS<Dog>. But now finally the class' type parameter, M, comes into play. How can we possibly have something like an ABS<Dog>? Whatever the type argument of ABS is, it should at least extends Number. This is why none of the three methods compile.
1. On the other hand compiles just fine, because it doesn't make any illegal declarations. It simply states that it has a generic type parameter K, it will accept an argument of type Object, and it will return a value of type K, whatever K happens to be. What is K? We can state it explicitly, like so:
We explicitly state that the type argument for this method call will be House. So the method promises to return a House instance, which we can then assign to our House variable. The argument the method takes can be anything, because it simply accepts Object. In this case, we pass a new Object(), but we also could have passed a String, or a Dog, or anything else.