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. By defining a class as generic you are making it type-safe i.e. it can act up on any datatype.
To define a generic class you need to specify the type parameter you are using in the angle brackets “<>” after the class name and you can treat this as datatype of the instance variable an proceed with the code.
 Live Demo
class Student<T>{
   T age;
   Student(T age){
      this.age = age;
   }
   public void display() {
      System.out.println("Value: "+this.age);
   }
}
public class GenericsExample {
   public static void main(String args[]) {
      Student<Float> std1 = new Student<Float>(25.5f);
      std1.display();
      Student<String> std2 = new Student<String>("25");
      std2.display();
      Student<Integer> std3 = new Student<Integer>(25);
      std3.display();
   }
}
Value: 25.5
Value: 25
Value: 25
Instead of the typed parameter in generics (T) you can also use “?”, representing an unknown type. You can use a wild card as a −
Type of parameter.
Field
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. Using this you can enable the usage of all the subtypes of a particular class as a typed parameter.
For example, if want to accept a Collection object as a parameter of a method with the typed parameter as a sub class of the number class, you just need to declare a wild card with the Number class as upper bound.
To create/declare an upper-bounded wildcard, you just need to specify the extends keyword after the “?” followed by the class name.
Following Java example demonstrates the creation of the upper-bounded wildcard.
 Live Demo
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.HashSet;
public class UpperBoundExample {
   public static void sampleMethod(Collection<? extends Number> col){
      for (Number num: col) {
         System.out.print(num+" ");
      }
      System.out.println("");
   }
   public static void main(String args[]) {
      ArrayList<Integer> col1 = new ArrayList<Integer>();
      col1.add(24);
      col1.add(56);
      col1.add(89);
      col1.add(75);
      col1.add(36);
      sampleMethod(col1);
      List<Float> col2 = Arrays.asList(22.1f, 3.32f, 51.4f, 82.7f, 95.4f, 625.f);
      sampleMethod(col2);
      HashSet<Double> col3 = new HashSet<Double>();
      col3.add(25.225d);
      col3.add(554.32d);
      col3.add(2254.22d);
      col3.add(445.21d);
      sampleMethod(col3);
   }
}
24 56 89 75 36
22.1 3.32 51.4 82.7 95.4 625.0
25.225 554.32 2254.22 445.21
If you pass a collection object other than type that is subclass of Number as a parameter to the sampleMethod() of the above program a compile time error will be generated.
 Live Demo
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.HashSet;
public class UpperBoundExample {
   public static void sampleMethod(Collection<? extends Number> col){
      for (Number num: col) {
         System.out.print(num+" ");
      }
      System.out.println("");
   }
   public static void main(String args[]) {
      ArrayList<Integer> col1 = new ArrayList<Integer>();
      col1.add(24);
      col1.add(56);
      col1.add(89);
      col1.add(75);
      col1.add(36);
      sampleMethod(col1);
      List<Float> col2 = Arrays.asList(22.1f, 3.32f, 51.4f, 82.7f, 95.4f, 625.f);
      sampleMethod(col2);
      HashSet<String> col3 = new HashSet<String>();
      col3.add("Raju");
      col3.add("Ramu");
      col3.add("Raghu");
      col3.add("Radha");
      sampleMethod(col3);
   }
}
UpperBoundExample.java:31: error: incompatible types: HashSet<String> cannot be converted to Collection<? extends Number>
      sampleMethod(col3);
                  ^
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error
upper-bounded wildcard enables the usage of all the subtypes of a particular class as a typed parameter.
Similarly, if we use the lower-bounded wildcards you can restrict the type of the “?” to a particular type or a super type of it.
For example, if want to accept a Collection object as a parameter of a method with the typed parameter as a super class of the Integer class, you just need to declare a wildcard with the Integer class as lower bound.
To create/declare a lower-bounded wildcard, you just need to specify the super keyword after the “?” followed by the class name.
Following Java example demonstrates the creation of the Lower-bounded wildcard.
 Live Demo
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Iterator;
public class LowerBoundExample {
   public static void sampleMethod(Collection<? super Integer> col){
      Iterator it = col.iterator();
         while (it.hasNext()) {
         System.out.print(it.next()+" ");
      }
   System.out.println("");
   }
   public static void main(String args[]) {
      ArrayList<Integer> col1 = new ArrayList<Integer>();
      col1.add(24);
      col1.add(56);
      col1.add(89);
      col1.add(75);
      col1.add(36);
      sampleMethod(col1);
      List<Object> col2 = Arrays.asList(22.1f, 3.32f, 51.4f, 82.7f, 95.4f, 625.f);
      sampleMethod(col2);
   }
}
24 56 89 75 36
22.1 3.32 51.4 82.7 95.4 625.0
If you pass a collection object other of type other than Integer and its super type as a parameter to the sampleMethod() of the above program a compile time error will be generated.
 Live Demo
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Iterator;
import java.util.HashSet;
public class LowerBoundExample {
   public static void sampleMethod(Collection<? super Integer> col){
      Iterator it = col.iterator();
         while (it.hasNext()) {
         System.out.print(it.next()+" ");
      }
      System.out.println("");
   }
   public static void main(String args[]) {
      ArrayList<Integer> col1 = new ArrayList<Integer>();
      col1.add(24);
      col1.add(56);
      col1.add(89);
      col1.add(75);
      col1.add(36);
      sampleMethod(col1);
      List<Object> col2 = Arrays.asList(22.1f, 3.32f, 51.4f, 82.7f, 95.4f, 625.f);
      sampleMethod(col2);
      HashSet<Double> col3 = new HashSet<Double>();
      col3.add(25.225d);
      col3.add(554.32d);
      col3.add(2254.22d);
      col3.add(445.21d);
      sampleMethod(col3);
   }
}
LowerBoundExample.java:34: error: incompatible types: HashSet<Double> cannot be converted to Collection<? super Integer>
      sampleMethod(col3);
                   ^
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
1 error
An unbounded wildcard is the one which enables the usage of all the subtypes of an unknown type i.e. any type (Object) is accepted as typed-parameter.
For example, if want to accept an ArrayList of object type as a parameter, you just need to declare an unbounded wildcard.
To create/declare a Unbounded wildcard, you just need to specify the wild card character “?” as a typed parameter within angle brackets.
Following Java example demonstrates the creation of the Unbounded wildcard.
import java.util.List;
import java.util.Arrays;
public class UnboundedExample {
   public static void sampleMethod(List<?> col){
      for (Object ele : col) {
         System.out.print(ele+" ");
      }
      System.out.println("");
   }
   public static void main(String args[]) {
      ArrayList<Integer> col1 = new ArrayList<Integer>();
      col1.add(24);
      col1.add(56);
      col1.add(89);
      col1.add(75);
      col1.add(36);
      sampleMethod(col1);
      ArrayList<Double> col2 = new ArrayList<Double>();
      col2.add(24.12d);
      col2.add(56.25d);
      col2.add(89.36d);
      col2.add(75.98d);
      col2.add(36.47d);
      sampleMethod(col2);
   }
}
24 56 89 75 36
24.12 56.25 89.36 75.98 36.47
If you pass an List object created from arrays (contains elements of primitive type) a compile time error will be generated.
 Live Demo
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class UnboundedExample {
   public static void sampleMethod(List<?> col){
      for (Object ele : col) {
         System.out.print(ele+" ");
      }
      System.out.println("");
   }
   public static void main(String args[]) {
      ArrayList<Integer> col1 = new ArrayList<Integer>();
      col1.add(24);
      col1.add(56);
      col1.add(89);
      col1.add(75);
      col1.add(36);
      sampleMethod(col1);
      ArrayList<Double> col2 = new ArrayList<Double>();
      col2.add(24.12d);
      col2.add(56.25d);
      col2.add(89.36d);
      col2.add(75.98d);
      col2.add(36.47d);
      sampleMethod(col2);
      List<Object> col2 = Arrays.asList(22.1f, 3.32f, 51.4f, 82.7f, 95.4f, 625.f);
      sampleMethod(col2);
   }
}
UnboundedExample.java:27: error: variable col2 is already defined in method main(String[])
      List<Object> col2 = Arrays.asList(22.1f, 3.32f, 51.4f, 82.7f, 95.4f, 625.f);
                  ^
1 error