Wildcard (Java): Difference between revisions

Content deleted Content added
Hamsooper (talk | contribs)
m Bounded wildcards: Added the clarification that wildcards cannot explicitly state both an upper and lower bound.
Example: Lists: Remove final keyword for function parameters
 
(10 intermediate revisions by 4 users not shown)
Line 1:
{{about|Java|the character|wildcard character}}
TheIn the [[Java (programming language)|Java programming language]], the '''wildcard''' <code>?</code> in [[Java (programming language)|Java]] is a special kind of type argument<ref>{{Cite web|title=Chapter 4. Types, Values, and Variables|url=https://docs.oracle.com/javase/specs/jls/se15/html/jls-4.html#jls-4.5.1|access-date=2020-11-03|website=docs.oracle.com}}</ref> that controls the [[type safety]] of the use of [[Generics in Java|generic]] (parameterized) types.{{sfn|Bloch|2018|loc=Chapter §5 Item 26: Don't use raw types|pp=117-122}} It can be used in variable declarations and instantiations<!--in special circumstances, see section below)--> as well as in method definitions, but not in the definition of a generic type.<ref name="gilad2004">{{citation|title=Generics in the Java Programming Language|url= http://www.oracle.com/technetwork/java/javase/generics-tutorial-159168.pdf|author=Gilad Bracha|date=June 2004|section=4. Wildcards|accessdate=6 March 2016}}</ref><ref>{{citation|url=http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.2|title=The Java Language Specification|section=8.1.2 Generic Classes and Type Parameters|publisher=Oracle|accessdate=6 March 2016}}</ref> This is a form of ''use-site'' [[variance annotation]], in contrast with the ''definition-site'' variance annotations found in [[C Sharp (programming language)|C#]] and [[Scala (programming language)|Scala]].
 
== Covariance for generic types ==
 
Unlike arrays (which are [[Covariance and contravariance (computer science)#Covariant arrays in Java and C#|covariant]] in Java{{sfn|Bloch|2018|loc=Chapter §5 Item 26: Don't use raw types|pp=117-122}}), different instantiations of a generic type are not compatible with each other, not even explicitly.{{sfn|Bloch|2018|loc=Chapter §5 Item 26: WithDon't use raw types|pp=117-122}} For example, the declarationdeclarations <code>Generic<Supertype> superGeneric; Generic<Subtype> subGeneric;</code> will cause the compiler wouldto report a conversion errorerrors for both castings <code>(Generic<Subtype>)superGeneric</code> and <code>(Generic<Supertype>)subGeneric</code>.
 
This incompatibility maycan be softened by the wildcard if <code>?</code> is used as an actual type parameter.{{sfn|Bloch|2018|loc=Chapter §5 Item 26: Don't use raw types|pp=117-122}} <code>Generic<?></code> is a supertype of all parameterizarions of the generic type <code>Generic</code>. This allows objects of type <code>Generic<Supertype></code> and <code>Generic<Subtype></code> to be safely assigned to a variable or method parameter of type <code>Generic<?></code>.{{sfn|Bloch|2018|loc=Chapter §5 Item 26: Don't use raw types|pp=117-122}} Using <code>Generic<? extends Supertype></code> allows the same, restricting compatibility to <code>Supertype</code> and its children.{{sfn|Bloch|2018|loc=Chapter §5 Item 31: Use bounded wildcards to increase API flexibility|pp=139-145}} Another possibility is <code>Generic<? super Subtype></code>, which also accepts both objects and restricts compatibility to <code>Subtype</code> and all its parents.{{sfn|Bloch|2018|loc=Chapter §5 Item 31: Use bounded wildcards to increase API flexibility|pp=139-145}}
 
== Wildcard as parameter type ==
 
In the body of a generic unit, the (formal) type parameter is handled like its [[bounded quantification|upper bound]] (expressed with <code>'''extends'''</code>; <code>Object</code> if not constrained).{{sfn|Bloch|2018|loc=Chapter §5 Item 31: Use bounded wildcards to increase API flexibility|pp=139-145}} If the return type of a method is the type parameter, the result (e.g. of type <code>?</code>) can be referenced by a variable of the type of the upper bound (or <code>Object</code>). In the other direction, the wildcard fits no other type, not even <code>Object</code>: If <code>?</code> has been applied as the formal type parameter of a method, no actual parameters can be passed to it. However, objects of the unknown type can be read from the generic object and assigned to a variable of a supertype of the upperbound.
 
Sample code for the <code>Generic<T '''extends''' UpperBound></code> class:
<syntaxhighlight lang="java5java">
class Generic <T extends UpperBound> {
private T t;
Line 21 ⟶ 23:
}
}
</syntaxhighlight>
 
Sample code that uses the <code>Generic<T '''extends''' UpperBound></code> class:
<syntaxhighlight lang="java">
...
final Generic<UpperBound> concreteTypeReference = new Generic<UpperBound>();
final Generic<?> wildcardReference = concreteTypeReference;
final UpperBound ub = wildcardReference.read(); // Object would also be OK
wildcardReference.write(new Object()); // type error
wildcardReference.write(new UpperBound()); // type error
concreteTypeReference.write(new UpperBound()); // OK
...
</syntaxhighlight>
 
== Bounded wildcards ==
 
A bounded wildcard is one with either an upper or a lower [[Inheritance (object-oriented programming)|inheritance]] constraint. The bound of a wildcard can be either a class type, [[Interface (Java)|interface]] type, array type, or type variable. Upper bounds are expressed using the '''extends''' keyword and lower bounds using the '''super''' keyword. Wildcards can state either an upper bound ''or'' a lower bound, but not both.
 
=== Upper bounds ===
An upper bound on a wildcard must be a subtype of the upper bound of the corresponding type parameter declared in the corresponding generic type.{{sfn|Bloch|2018|loc=Chapter §5 Item 31: Use bounded wildcards to increase API flexibility|pp=139-145}} An example of a wildcard that explicitly states an upper bound is:
 
<code>Generic<? '''extends''' SubtypeOfUpperBound> referenceConstrainedFromAbove;</code>
Line 46 ⟶ 53:
<code>Generic<? '''super''' SubtypeOfUpperBound> referenceConstrainedFromBelow;</code>
 
can hold any parameterization of <code>Generic</code> whose any type argument is both a subtype of the corresponding type parameter's upper bound and a supertype of <code>SubtypeOfUpperBound</code>.{{sfn|Bloch|2018|loc=Chapter §5 Item 31: Use bounded wildcards to increase API flexibility|pp=139-145}}
 
== Object creation with wildcard ==
Line 61 ⟶ 68:
 
In the Java Collections Framework, the class <code>List<MyClass></code> represents an ordered collection of objects of type <code>MyClass</code>.
Upper bounds are specified using <code>'''extends'''</code>:
A <code>List<? '''extends''' MyClass></code> is a list of objects of some subclass of <code>MyClass</code>, i.e. any object in the list is guaranteed to be of type <code>MyClass</code>, so one can iterate over it using a variable of type <code>MyClass</code><ref>[[Inheritance (object-oriented programming)]]</ref>
<syntaxhighlight lang="java5java">
public void doSomething(List<? extends MyClass> list) {
for (final MyClass object : list) { // OK
// do something
}
Line 71 ⟶ 78:
</syntaxhighlight>
However, it is not guaranteed that one can add any object of type <code>MyClass</code> to that list:
<syntaxhighlight lang="java5java">
public void doSomething(List<? extends MyClass> list) {
final MyClass m = new MyClass();
list.add(m); // Compile error
}
</syntaxhighlight>
 
The converse is true for lower bounds, which are specified using <code>'''super'''</code>:
A <code>List<? '''super''' MyClass></code> is a list of objects of some superclass of <code>MyClass</code>, i.e. the list is guaranteed to be able to contain any object of type <code>MyClass</code>, so one can add any object of type <code>MyClass</code>:
<syntaxhighlight lang="java5java">
public void doSomething(List<? super MyClass> list) {
final MyClass m = new MyClass();
list.add(m); // OK
}
</syntaxhighlight>
However, it is not guaranteed that one can iterate over that list using a variable of type <code>MyClass</code>:
<syntaxhighlight lang="java5java">
public void doSomething(List<? super MyClass> list) {
for (final MyClass object : list) { // Compile error
// do something
}
Line 95 ⟶ 102:
</syntaxhighlight>
 
In order to be able to do both add objects of type <code>MyClass</code> to the list and iterate over it using a variable of type <code>MyClass</code>, a <code>List<MyClass></code> is needed, which is the only type of <code>List</code> that is both <code>List<? '''extends''' MyClass></code> and <code>List<? '''super''' MyClass></code>.<ref>[[Java syntax|Java syntax(Generics)]]</ref>
 
The mnemonics PECS (Producer Extends, Consumer Super) from the book '''Effective Java''' by [[Joshua Bloch]] gives an easy way to remember when to use wildcards (corresponding to Covariance and Contravariance) in Java.{{sfn|Bloch|2018|loc=Chapter §5 Item 31: Use bounded wildcards to increase API flexibility|pp=139-145}}
 
==See also==
Line 105 ⟶ 112:
* [[Generics in Java#Type wildcards]] section explains lower and upper wildcard bounds
 
== ReferencesCitations ==
 
{{Reflist}}
 
== References ==
*{{cite book | title= "Effective Java: Programming Language Guide" |last=Bloch| first=Joshua| publisher=[[Addison-Wesley]] | edition=third | isbn=978-0134685991| year=2018}}
* The Java Language Specification, Third Edition (Sun), {{ISBN|978-0-321-24678-3}} http://java.sun.com/docs/books/jls/
* Java Tutorials, Lesson Generics http://download.oracle.com/javase/tutorial/java/generics/index.html