I'm trying to understand Generic types in Java, and in theory it looks understandable, but when I need to apply it to real code I have problem. I want to declare abstract method which will return generic type. Let's assume that I have some empty interface called Magicable and 2 class implements it: Magican and Witch. Now I wonder what is the difference between those 3 declarations:
/*1*/protected abstract <T extends Magicable> List<T> getMagicables();
/*2*/protected abstract List<? extends Magicable> getMagicables();
/*3*/protected abstract List<Magicable> getMagicables();
In first case I have problem when I want to implement body of this method in some class which extends the abstract class:
@Override
protected List<Magican> getMagicable() {..}
I have warning message:
Type safety: The return type List<Magican> for getMagicable() from the type MagicanService needs unchecked conversion to conform to List<Magicable> from the type MagicableService.
In second case I don't have this warning, but I have problem in abstract class in which I declared above abstract method:
public void <T extends Magicable> T getOneFromList() {
List<T> list = getMagicables();
//.....
}
In this case I have compilation error in getMagicables() call:
Type mismatch: cannot convert from List<capture#2-of ? extends Magicable> to List<T>
Third case causes compilation errors in both abovementioned places of code. I don't think if it is properly solution in my case.
We can use the Java Wildcard as a local variable, parameter, field or as a return type. But, when the generic class is instantiated or when a generic method is called, we can't use wildcards. The wildcard is useful to remove the incompatibility between different instantiations of a generic type.
The question mark (?) is known as the wildcard in generic programming. It represents an unknown type. The wildcard can be used in a variety of situations such as the type of a parameter, field, or local variable; sometimes as a return type.
Abstract is used to define something that requires additional definition of functionality before it is considered "complete" (or concrete in Java-certification-test-terms). Generic means it's a class that can handle a wide variety of data types that you define when you instantiate the class.
Due to extensive capture conversion, in most places, compiler treats wildcards as if they are type variables. Therefore indeed programmer can replace wildcard with type variables in such places, a sort of manual capture conversion.
What are wildcards arguments in Generics In Java? Generics is a concept in Java where you can enable a class, interface and, method, accept all (reference) types as parameters. In other words it is the concept which enables the users to choose the reference type that a method, constructor of a class accepts, dynamically.
Wild Cards (?) Generic methods are methods that introduce their own type parameters. This is similar to declaring a generic type at class level, but the type parameter’s scope is limited to the method where it is declared. Static and non-static generic methods are allowed, as well as generic class constructors.
Local field. The only restriction on wilds cards is that you cannot it as a type argument of a generic method while invoking it. Java provides 3 types of wild cards namely upper-bounded, lower-bounded, un-bounded. Upper bounds in wild cards is similar to the bounded type in generics.
We generally use this wildcard when the code inside the method is using the Object functionality and also when the code inside the method does not depend upon the parameter type. So if we briefly wrap up about each wildcard, we can say their usage in the following three ways: Upper bound Wildcard: ? extends Type. Lower bound Wildcard: ? super Type.
- First case
Just declare your method with:
@Override
protected <T extends Magicable> List<T> getMagicables() {
List<T> list = ...
return list
}
If you really want this:
@Override
protected List<Magican> getMagicable() {..}
you may have to declare your generic T into the class defintion
public abstract class AbstractKlass<T extends Magicable> {
protected abstract List<T> getMagicables();
}
then in your Subclass:
public class MySubClass extends AbstractKlass<Magican> {
@Override
protected List<Magican> getMagicables() {
...
}
}
- Second case
The compilation error is normal because <? extends Magicable>
from the signature of method means you don't care what's inside your list from the moment you can consider those elements just as Magicable. When doing a call
List<T> list = getMagicables();
You want to take care of the type T without knowing it. In other terms, there are 3 use cases: T is Magicable (OK), T is Magician (Wrong because getMagicables may return a list of Witch) and T is Witch (Wrong too).
- Why I use
? extends Magicable
instead of justMagicable
in lists
Because List<Magician>
is a subtype of List<? extends Magicable>
but not a subtype of List<Magicable>
. This is usefull for parameters of methods.
public void doIt(List<? extends Magicable> list) {
// you can't add a Magician here
}
may be used as
List<Witch> list = ...
doIt(list);
But if you have
public void doIt(List<Magicable> list) {
// you can add a Magician here
}
You can't use it as
List<Witch> list = ...
doIt(list); // compile error
For the part of the problem, you did show us, method /* 3 */ is sufficient, you do not need the generics for that part of your code. But you need to respect substitutability:
You get the error in #1 because the sub-type method is restricting the range of the return type: a Magican
is Magicable
but not vice versa. Super-types of Magicable
are allowed in the sub-type. The sub-type method has to be substitutable for the super-type method, which is not the case in your example.
The error in #2 is due to the nature of the wildcard ?
: ? extends Magicable
and T extends Magicable
need not be the same type. If T
is declared in the class scope, e.g. class Magican<T> implements Magicable<T>
(of course your interface needs to declare T in this case) all occurrences of T
in your type would refer to the same class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With