简体   繁体   中英

Why can't I use the wildcard (?) as type of parameter, field, local variable, or as return type of a method?

The Oracle doc about Wildcards in generics says,

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).

I have tried all four in the following class, and got compiler errors on each one. Why? What am I doing wrong?

public class MainClass {
    private ? instanceFieldWithWildCardType;//ERROR
    private static ? staticFieldWithWildCardType;//ERROR

    private void methodWithWildCardParam(? param) {}//ERROR

    private void methodWithWildCardLocalVariable() {
        ? localVariableWithWildCardType;//ERROR
    }

    private ? methodWithWildCardReturnType() {//ERROR
        return null;
    }

    private void methodWithWildCardParam(? param) {}//ERROR

}

The ? character is the wildcard type argument .

The article begins with

In generic code , the question mark (?), called the wildcard, represents an unknown type.

The only place you can use that syntax is as part of generic code, ie. a generic type argument. The next sentence refers to generic code using the wildcard. So, for example

as the type of a parameter

you could have

public static void shuffle(List<?> list) {

Or for

as a local variable

public void method() {
    List<?> list = Arrays.asList(1, 2, 3);
    Collections.shuffle(list);
    System.out.println(list);
}

But

The wildcard is never used as a type argument for a generic method invocation, a generic class instance creation, or a supertype.

You can't use it as

Arrays.<?>asList(1, "", '5');
List<?> list = new ArrayList<?>();
...
public class MyList implements List<?> {/* whatever */}

The tutorial is terribly phrased. You cannot use a wildcard for any of the things listed. You can use a generic type with a wildcard in it for those things.

public class Example {
    ? field1;        // invalid
    List<?> field2;  // valid

    private ? method1(? param) {return param;}              // invalid
    private List<?> method2(List<?> param) {return param;}  // valid

    private void method3() {
        ? var1;        // invalid
        List<?> var2;  // valid
    }
}

Wildcard can be used with <> operator in a generics concept introduced in java 5, used to represent unknown type . Generics is used to define a class with member in generalized format.If you want to provide facility that while creating the object, user will specify the type of member then you can use the concept of generics. It can be used only for the instance member can't be used with static member cause memory for static will be allocated only once.

Wildcard concept introduced in generics to restrict unknow type, let's say I have list which has wildcard and this wildcard extend Number wrapper class. That means list can work with Integer, Long, Short, Byte cause they extend Number wrapper class but not with String as String class do not extends Number wrapper class.

List<? extends Number> lt = new ArrayList<>();

Coming to you program, you have used wrong syntax, as i have mentioned wildcard can be used with <> operator.

We can't use wildcard while instantiating class like mentioned bellow -

 List<?> lt = new ArrayList<?>();

but we can use generics to provide the field as unknown type like I,N,S in employee class. It's type we will provide while creating the object of the class -

class Employee<I,N,S>
{
    I eid;
    N empName;
    S empSalary;
}

class Name
{
   String firstName;
   String middleName;
   String lastName;
}

class salary
{
    double basic;
    float it;
    float tds;
    double netsal;
}

class CustomId
{
   int empId;
   String department;
   int branchId;
} 

main method 
------------

    Employee<Integer,String,Double> emp = new Employee<>();
    Employee<String,Name,Salary> emp2 = new Employee<>();
    Employee<CustomId,String,Salary> emp3 = new Employee<>();

Wildcard as method parameter -

public void sortList(List<?> lt)
{
   // code to sort the list whether it is integer, String etc
}
call sortList() method
-----------------------
List<String> lt = new List<>();
lt.add("sss");
lt.add("aaa");
sortList(lt);

List<Integer> lt = new List<>();
lt.add(11);
lt.add(12);
sortList(lt);

Declaring local variable as wildcard -

 List<?> lt = new ArayList<String>();
 List<?> lt = new ArayList<Integer>();

We can use wildcard and generics as return type of method. Here is the example of generics as return type of method -

public T getName(ClassName obj, Key key)
{
    return (Type<T>)obj.getType(Key);
}

Here is the example of wildcard as return type of method -

    List<?> method(List<?> data) 
    {
        return data;    
    }

Wildcards does not have individual existence. They are always used as type parameter of Generic classes Ex : List<? extends Number> List<? extends Number> .I give one example covering all scenarios.

import java.util.ArrayList;
import java.util.List;

class A{

    // I have not make use of this anywhere in this example
    List<? extends Number> l1; //Field;

    //Just taking l2 as parameter
    //Wont be using it also
    //Just tp show wildcard with generic as parameter
    public List<? extends Number> operate(List<? extends Number> l2){ //As return Type; Not recommended Approach

        List<Integer> list = new ArrayList<>();
        list.add(new Integer(6));
        return list;
    }

}



public class Main {

    public static void main(String[] args) {

        List<? extends Number> ar = new ArrayList<Integer>(); //Local Variable
        A obj = new A();
        System.out.println(obj.operate(ar));
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM