Почему я не могу использовать подстановочный знак (?) как тип параметра, поля, локальной переменной или как возвращаемый тип метода?

В документе 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

}

person Solace    schedule 23.06.2016    source источник
comment
Потому что это недопустимый синтаксис. Я не вижу никаких дженериков, только ?s.   -  person Sean Bright    schedule 23.06.2016
comment
Лучше прочитайте подразделы (docs.oracle.com/javase/tutorial/ java/generics/upperBounded.html) подстановочных знаков в общей главе. Вы не можете использовать подстановочные знаки напрямую для замены типов. Также см. множество других примеров, предоставленных различными источниками в Интернете.   -  person S.K. Venkat    schedule 13.07.2016


Ответы (4)


Учебник ужасно сформулирован. Вы не можете использовать подстановочный знак ни для одной из перечисленных вещей. Для этих целей можно использовать универсальный тип с подстановочным знаком.

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
    }
}
person user2357112 supports Monica    schedule 23.06.2016
comment
Я не уверен, что ужасная формулировка подходит для описания содержания этого урока. Возможно, вводящие в заблуждение или просто неправильные были бы лучше. Я блуждаю, если мы можем сказать, что мы можем использовать общий тип в качестве параметра (класса, интерфейса, метода) и подстановочный знак в качестве аргумента, используя такой параметризованный класс/интерфейс/метод - person Zbyszek; 30.10.2020

Символ ? является подстановочным знаком . аргумент.

Статья начинается с

В универсальном коде знак вопроса (?), называемый подстановочным знаком, представляет неизвестный тип.

Единственное место, где вы можете использовать этот синтаксис, — это часть общего кода, т.е. аргумент универсального типа. Следующее предложение относится к универсальному коду с использованием подстановочного знака. Так, например

как тип параметра

ты мог бы

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 */}
person Sotirios Delimanolis    schedule 23.06.2016
comment
Также стоит отметить, что тот же код в последнем фрагменте был бы действительным, если бы он использовал T вместо ? для его ввода. - person Jeremy Kato; 23.06.2016
comment
Во всех этих примерах ? не используется как тип, а List<?> используется как тип. ? отличается от List<?>. я в замешательстве :с - person Solace; 23.06.2016
comment
@Solace ? — это подстановочный знак введите аргумент. Его нельзя использовать вне контекста универсальных типов. - person Sotirios Delimanolis; 23.06.2016
comment
? является частью параметра типа, а не типом сам по себе. Это недопустимый синтаксис для имени типа, поэтому, когда вы использовали его в качестве имени типа - КАБЛОУ! - person Lew Bloch; 23.06.2016

Подстановочный знак можно использовать с оператором ‹> в концепции дженериков, представленной в 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;    
    }
person RCS    schedule 23.06.2016

Подстановочные знаки не имеют индивидуального существования. Они всегда используются в качестве параметра типа универсальных классов Пример: 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));
    }
}
person Number945    schedule 23.03.2017