为什么我不能使用通配符(?)作为参数,字段,局部变量的类型,或作为方法的返回类型?

时间:2016-06-23 17:51:48

标签: java generics wildcard bounded-wildcard unbounded-wildcard

Oracle doc about Wildcards in generics说,

  

通配符可用于各种情况:作为a的类型   参数字段本地变量;有时作为返回类型   (虽然更好的编程实践更具体)。

我已经尝试了以下类中的所有四个,并且每个都遇到了编译器错误。为什么?我做错了什么?

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

}

4 个答案:

答案 0 :(得分:9)

?字符是wildcard type argument

文章以

开头
  

在通用代码中,问号(?),称为通配符,   代表一种未知的类型。

您可以使用该语法的唯一地方是通用代码的一部分,即。泛型类型参数。下一句是指使用通配符的通用代码。所以,例如

  

作为参数的类型

你可以

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

  

作为局部变量

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

但是

  

通配符从不用作泛型方法的类型参数   调用,泛型类实例创建或超类型。

您无法将其用作

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

答案 1 :(得分:9)

教程非常明确。您不能对列出的任何内容使用通配符。您可以使用泛型类型,其中包含通配符

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
    }
}

答案 2 :(得分:2)

通配符可与&lt;&gt;一起使用在Java 5中引入的泛型概念中的运算符用于表示未知类型。泛型用于定义具有通用格式成员的类。如果要在创建对象时提供工具,用户将指定成员的类型,然后您可以使用泛型的概念。它只能用于实例成员不能与静态成员一起使用,因为静态内存只会被分配一次。

在泛型中引入的通配符概念用于限制unknow类型,假设我有一个包含通配符的列表,这个通配符扩展了数字包装类。这意味着列表可以使用Integer,Long,Short,Byte,因为它们扩展了Number包装类,但没有使用String作为String类,不扩展Number包装类。

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

来到你的程序,你使用了错误的语法,因为我已经提到过,通配符可以和&lt;&gt;一起使用操作

  

我们不能在实例化上面提到的类时使用通配符 -

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

但是我们可以使用泛型来提供字段作为员工类中的I,N,S等未知类型。这是我们在创建类的对象时将提供的类型 -

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<>();
  

通配符作为方法参数 -

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

将局部变量声明为通配符 -

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

我们可以使用通配符和泛型作为返回类型的方法。   以下是泛型作为返回类型方法的示例 -

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

以下是通配符作为返回类型的方法的示例 -

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

答案 3 :(得分:1)

通配符没有个人存在。它们总是用作Generic类Ex:List<? extends Number>的类型参数。我给出了一个涵盖所有场景的示例。

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));
    }
}