16

关于泛型通配符的 Oracle文档说,

通配符可用于多种情况:作为参数字段局部变量的类型;有时作为返回类型 (尽管更具体的是更好的编程实践)。

我在下面的课程中尝试了所有四个,并且每个都得到了编译器错误。为什么?我究竟做错了什么?

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

4 回答 4

10

?字符是通配符类型参数

文章开头是

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

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

作为参数的类型

你可以有

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 */}
于 2016-06-23T18:00:18.693 回答
10

该教程的措辞非常糟糕。您不能对列出的任何内容使用通配符。您可以使用带有通配符的泛型类型来处理这些事情。

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
    }
}
于 2016-06-23T20:49:40.873 回答
2

在 java 5 中引入的泛型概念中,通配符可以与<> 运算符一起使用,用于表示未知类型。泛型用于以通用格式定义具有成员的类。如果您想提供在创建对象时用户指定成员类型的便利,那么您可以使用泛型的概念。它只能用于实例成员不能与静态成员一起使用,因为静态内存只会分配一次。

泛型中引入了通配符概念以限制未知类型,假设我有一个包含通配符的列表,并且这个通配符扩展了 Number 包装类。这意味着列表可以与 Integer、Long、Short、Byte 一起使用,因为它们扩展了 Number 包装类,但不能与 String 一起使用,因为 String 类不扩展 Number 包装类。

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

来到你的程序,你使用了错误的语法,因为我已经提到通配符可以与 <> 运算符一起使用。

我们不能在实例化类时使用通配符,如下所述 -

 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;    
    }
于 2016-06-23T19:59:44.753 回答
1

通配符没有单独的存在。它们总是用作泛型类的类型参数 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));
    }
}
于 2017-03-23T06:42:17.103 回答