This question already has an answer here:
Type parameter vs unbounded wildcard
(1 answer)
Closed 7 years ago.
I have a method where I want to accept class types that must extend an abstract class. What is the difference between
<T extends AbstractClass> void myMethod(Class<T> clazz);
and
void myMethod(Class<? extends AbstractClass> clazz); ?
I wouldn't be able to directly reference the type inside the method in the second case. Is there any difference in which class types could be passed to these two methods?
No, there is no difference between the argument types compatible with the two method signatures you presented. Personally, I would use the parameterized version if I needed to reference the exact type represented by the argument, but otherwise I would use the wildcard version.
In the 1st one you will also be able to return T (or any type parameterized with T: List<T>, Set<T> and so on...) , without needing to cast it
<T extends AbstractClass> T myMethod(Class<T> clazz);
And use it as :
Subclass parameterInstance =...
Subclass i1 = myMethod(parameterInstance.getClass());
This question has been asked many places, notably here and here.
Both questions deal primarily with unbounded wildcards and generic types but the same principles apply here. I'd also recommend reading one of the links (Angelika Langer - Java Generics FAQs) provided by one of the answers to the other questions (placed here for convenient).
Whilst in your specific case there is no difference, the difference comes down simply to how you would be dealing with the type data internally (within the method). Go with what seems to describe your purpose the best. If you are dealing with data of unknown type and you require the specific input type to be specifically usable within the method, you'll need to go with the generics approach. If on the other hand, you do not and can suffice with treating all input data as simply of the bounding type (e.g. AbstractClass in your case) you may go with the bounded wildcard approach.
Related
Is it feasible to say that generic wildcard types should not be used in return parameters of a method?
In other words, does make sense to declare an interface like the following:
interface Foo<T> {
Collection<? extends T> next();
}
Additionally, is it ok to say that generic wildcard types does make sense only at method's parameter declaration?
The main benefit of using wildcard types, say in method formal parameter, is to provide flexibility to the user to pass, say any type of Collection, or List or anything that implements Collection (assuming that the collection is declared like Collection<?>). You would often find yourself using wildcard types in formal parameters.
But ideally you should avoid using them as return type of your method. Because that way, you would force the user of that method to use wildcard types at the caller end, even if they didn't want to. By using wildcard types, you're saying that, hey! this method can return any type of Collection, so it's your job to take care of that. You shouldn't do that. Better to use bounded type parameter. With bounded type parameter, the type will be inferred based on the type you pass, or the target type of the method invocation.
And here's a quote from Effective Java Item 28:
Do not use wildcard types as return types. Rather than providing
additional flexibility for your users, it would force them to use
wildcard types in client code.
Properly used, wildcard types are
nearly invisible to users of a class. They cause methods to accept the
parameters they should accept and reject those they should reject. If
the user of a class has to think about wildcard types, there is
probably something wrong with the class’s API.
No, it is not feasible to say this.
Or to put it that way: It does make sense to have such an interface.
Imagine the following
interface Foo<T>
{
Collection<? extends T> next();
}
class FooInteger implements Foo<Number>
{
private final List<Integer> integers = new ArrayList<Integer>();
void useInternally()
{
integers.add(123);
Integer i = integers.get(0);
}
#Override
public Collection<? extends Number> next()
{
return integers;
}
}
// Using it:
Foo<Number> foo = new FooInteger();
Collection<? extends Number> next = foo.next();
Number n = next.iterator().next();
If you wrote the return type as Collection<T>, you could not return a collection containing a subtype of T.
Whether or not it is desirable to have such a return type depends on the application case. In some cases, it may simply be necessary. But if it is easy to avoid, then you can do this.
EDIT: Edited the code to point out the difference, namely that you might not always be able to choose the type internally. However, in most cases returning something that involves a wildcard can be avoided - and as I said, if possible, it should be avoided.
The example sketched above should still be considered as an example to emphasize the key point. Although, of course, such an implementation would be a bad practice, because it is exposing an internal state.
In this and similar cases, one can often return something like a
return Collections.<Number>unmodifiableList(integers);
and by this, declare the return type as Colletion<Number>: The unmodifiableList method solves the problem of the exposed internal state, and has the neat property that it allows changing the type parameter to a supertype, because the list is then... well, unmodifiable anyhow.
https://rules.sonarsource.com/java/RSPEC-1452
It is highly recommended not to use wildcard types as return types.
Because the type inference rules are fairly complex it is unlikely the
user of that API will know how to use it correctly. Let's take the
example of method returning a "List<? extends Animal>". Is it possible
on this list to add a Dog, a Cat, ... we simply don't know. And
neither does the compiler, which is why it will not allow such a
direct use. The use of wildcard types should be limited to method
parameters.
This rule raises an issue when a method returns a wildcard type.
Noncompliant Code Example
List<? extends Animal> getAnimals(){...}
Compliant Solution
List<Animal> getAnimals(){...} or
List<Dog> getAnimals(){...}
Referring to : Wildcard Capture Helper Methods
It says to create a helper method to capture the wild card.
public void foo(List<?> i) {
fooHelper(i);
}
private <T> void fooHelper(List<T> l) {
l.set(0, l.get(0));
}
Just using this function below alone doesn't produce any compilation errors, and seems to work the same way. What I don't understand is: why wouldn't you just use this and avoid using a helper?
public <T> void foo(List<T> l) {
l.set(0, l.get(0));
}
I thought that this question would really boil down to: what's the difference between wildcard and generics? So, I went to this: difference between wildcard and generics.
It says to use type parameters:
1) If you want to enforce some relationship on the different types of method arguments, you can't do that with wildcards, you have to use type parameters.
But, isn't that exactly what the wildcard with helper function is actually doing? Is it not enforcing a relationship on different types of method arguments with its setting and getting of unknown values?
My question is: If you have to define something that requires a relationship on different types of method args, then why use wildcards in the first place and then use a helper function for it?
It seems like a hacky way to incorporate wildcards.
In this particular case it's because the List.set(int, E) method requires the type to be the same as the type in the list.
If you don't have the helper method, the compiler doesn't know if ? is the same for List<?> and the return from get(int) so you get a compiler error:
The method set(int, capture#1-of ?) in the type List<capture#1-of ?> is not applicable for the arguments (int, capture#2-of ?)
With the helper method, you are telling the compiler, the type is the same, I just don't know what the type is.
So why have the non-helper method?
Generics weren't introduced until Java 5 so there is a lot of code out there that predates generics. A pre-Java 5 List is now a List<?> so if you were trying to compile old code in a generic aware compiler, you would have to add these helper methods if you couldn't change the method signatures.
I agree: Delete the helper method and type the public API. There's no reason not to, and every reason to.
Just to summarise the need for the helper with the wildcard version: Although it's obvious to us as humans, the compiler doesn't know that the unknown type returned from l.get(0) is the same unknown type of the list itself. ie it doesn't factor in that the parameter of the set() call comes from the same list object as the target, so it must be a safe operation. It only notices that the type returned from get() is unknown and the type of the target list is unknown, and two unknowns are not guaranteed to be the same type.
You are correct that we don't have to use the wildcard version.
It comes down to which API looks/feels "better", which is subjective
void foo(List<?> i)
<T> void foo(List<T> i)
I'll say the 1st version is better.
If there are bounds
void foo(List<? extends Number> i)
<T extends Number> void foo(List<T> i)
The 1st version looks even more compact; the type information are all in one place.
At this point of time, the wildcard version is the idiomatic way, and it's more familiar to programmers.
There are a lot of wildcards in JDK method definitions, particularly after java8's introduction of lambda/Stream. They are very ugly, admittedly, because we don't have variance types. But think how much uglier it'll be if we expand all wildcards to type vars.
The Java 14 Language Specification, Section 5.1.10 (PDF) devotes some paragraphs to why one would prefer providing the wildcard method publicly, while using the generic method privately. Specifically, they say (of the public generic method):
This is undesirable, as it exposes implementation information to the caller.
What do they mean by this? What exactly is getting exposed in one and not the other?
Did you know you can pass type parameters directly to a method? If you have a static method <T> Foo<T> create() on a Foo class -- yes, this has been most useful to me for static factory methods -- then you can invoke it as Foo.<String>create(). You normally don't need -- or want -- to do this, since Java can sometimes infer those types from any provided arguments. But the fact remains that you can provide those types explicitly.
So the generic <T> void foo(List<T> i) really takes two parameters at the language level: the element type of the list, and the list itself. We've modified the method contract just to save ourselves some time on the implementation side!
It's easy to think that <?> is just shorthand for the more explicit generic syntax, but I think Java's notation actually obscures what's really going on here. Let's translate into the language of type theory for a moment:
/* Java *//* Type theory */
List<?> ~~ ∃T. List<T>
void foo(List<?> l) ~~ (∃T. List<T>) -> ()
<T> void foo(List<T> l) ~~ ∀T.(List<T> -> ()
A type like List<?> is called an existential type. The ? means that there is some type that goes there, but we don't know what it is. On the type theory side, ∃T. means "there exists some T", which is essentially what I said in the previous sentence -- we've just given that type a name, even though we still don't know what it is.
In type theory, functions have type A -> B, where A is the input type and B is the return type. (We write void as () for silly reasons.) Notice that on the second line, our input type is the same existential list we've been discussing.
Something strange happens on the third line! On the Java side, it looks like we've simply named the wildcard (which isn't a bad intuition for it). On the type theory side we've said something _superficially very similar to the previous line: for any type of the caller's choice, we will accept a list of that type. (∀T. is, indeed, read as "for all T".) But the scope of T is now totally different -- the brackets have moved to include the output type! That's critical: we couldn't write something like <T> List<T> reverse(List<T> l) without that wider scope.
But if we don't need that wider scope to describe the function's contract, then reducing the scope of our variables (yes, even type-level variables) makes it easier to reason about those variables. The existential form of the method makes it abundantly clear to the caller that the relevance of the list's element type extends no further than the list itself.
This question already has answers here:
Difference between generic type and wildcard type
(8 answers)
Closed 8 years ago.
In the Java generics tutorial it says that <?> in a generic method means "unknown".
But I don't understand how <?> is different than <T>. Both mean that you can pass in any type-parameter you'd like. Please explain this operator.
The following excerpts come from http://docs.oracle.com/javase/tutorial/java/generics/wildcards.html
In generic code, the question mark (?), called the wildcard,
represents an unknown type. The wildcard can be used in a variety of
situations: as the type of a parameter, field, or local variable;
sometimes as a return type (though it is better programming practice
to be more specific). The wildcard is never used as a type argument
for a generic method invocation, a generic class instance creation, or
a supertype.
And another:
The unbounded wildcard type is specified using the wildcard character
(?), for example, List. This is called a list of unknown type.
There are two scenarios where an unbounded wildcard is a useful
approach:
If you are writing a method that can be implemented using functionality provided in the Object class.
When the code is using methods in the generic class that don't depend on the type parameter. For example, List.size or List.clear. In
fact, Class is so often used because most of the methods in
Class do not depend on T.
The second bullet makes the biggest distinction. Use '?' When you don't need to call operations on the actual type. See the link provided if you need more details. There are several sub sections under this wild cards section that cover different points so don't stop with just the page you are directed to.
This question already has answers here:
Is List<Dog> a subclass of List<Animal>? Why are Java generics not implicitly polymorphic?
(19 answers)
Closed 8 years ago.
Making a API for internal use, I need some Java abstraction and I don't know how to do it.
There is an Interface A with derived interfaces.
Let's say one of the extended interfaces of A is called B.
And let's say there is an class C implementing B.
I have a Factory/Pool class F from which I want to get a list of instances (or set or similar collection).
What I want is basically this:
List<B> instances = F.getAllSuitableInstances(parameters);
Get me all the instances specified by my parameters as a collection of B.
First attempt was with this function signature
public List<A> getAllSuitableInstances(parameters);
but when I try to cast the resulting List to a List for use, I
get told "incompatible types" - even though B is derived from A.
So I tried what the java libraries do:
public <T> List<T> getAllSuitableInstances(parameters, T);
and try calling that with B as second parameter. But that doesn't work
either, since T has to be supplied as an instance for some reason, and
interfaces cannot have instances.
I know I could use <?> with casting but I'd like to make this as typesafe as possible.
So, what is the (best) way to get this done?
even though B is derived from A.
You have to be careful here -- Java's generics are invariant, meaning that Something<Superclass> is not a superclass of Something<Subclass> (e.g. List<Number> is not a superclass of List<Integer>). There are plenty of questions on SO about this, so I won't repeat information that other people can explain much more effectively, like here and here.
As for your second signature, it seems to me that the T in (parameters, T) is unnecessary.
public <T> List<T> getAllSuitableInstance(parameters);
should work, unless I'm misunderstanding your requirements. The disadvantage of this is that T could be anything, so you're somewhat limited in the methods you can invoke on objects of type T, but if you aren't doing that then no concern is warranted.
If the methods in your interfaces are necessary to get your method working (doesn't seem like it, but just in case), you can always add bounds (e.g. public <T extends A> List<T>...) to your generic type, so the compiler knows that all instances of T inside your method are type A or subtypes of A.
If you need to use the type of T in your method (say for instanceof checks), one option is passing in a Class object and using its methods to perform the runtime equivalent of instanceof checks and casting (among other options):
public <T> List<T> getAllSuitableInstance(parameters, Class<? extends T> clazz); // Might be able to use just Class<T> too
Hopefully that helps. Let me know if I got something wrong about what you needed.
This is a common misunderstanding when it comes to programming with generics, but it is an important concept to learn
when we have two concrete types A and B (for example, Number and Integer), MyClass<A> has no relationship to MyClass<B>, regardless of whether or not A and B are related.
The common parent of MyClass<A> and MyClass<B> is Object.
No need to even pass the class as you mentioned in second option
this should work for you
public <T> List<T> getAllSuitableInstances(parameters) {
List<T> list = new ArrayList<>();
//content add to list
return list;
}
I just saw this C# question and wondered, if something similar could happen in Java. It can, with
class A<T> {
A(Integer o) {...}
A(T o) {...}
}
the call
new A<Integer>(43);
is ambiguous and I see no way how to resolve it. Is there any?
You can drop the generics during construction (and suppress a warning):
A<Integer> a = new A(42);
or, less preferably use reflection (where again you'd have to suppress warnings)
Constructor<A> c = A.class.getDeclaredConstructor(Integer.class);
A<Integer> a = c.newInstance(42);
Yes, members of a parameterized type JLS3#4.5.2 can end up in conflicts that are precluded in a normal class declaration(#8.4.8). It's pretty easy to come up with many examples of this kind.
And in Java, neither constructor in your example is more specific than the other, because there is no subtyping relation between T and Integer. see also Reference is ambiguous with generics
If method overloading creates this kind of ambiguity, we can usually choose to use distinct method names. But constructors cannot be renamed.
More sophistries:
If <T extends Integer>, then indeed T is a subtype of Integer, then the 2nd constructor is more specific than the 1st one, and the 2nd one would be chosen.
Actually javac wouldn't allow these two constructors to co-exist. There is nothing in the current Java language specification that forbids them, but a limitation in the bytecode forces javac to forbid them. see Type Erasure and Overloading in Java: Why does this work?
Another point: If <T extends Integer>, since Integer is final, T can only be Integer, so Integer must also be a subtype of T, therefore isn't the 2nd constructor also more specific than the 1st?
No. final isn't considered in subtyping relations. It is actually possible to drop final from Integer one day, and Java even specifies that removing final does not break binary compatibility.
Indeed, it is ambiguous, and so doesn't compile if you try new A<Integer>(new Integer(0)).