Почему я не могу использовать подстановочный знак (?) В качестве типа параметра, поля, локальной переменной или в качестве возвращаемого типа метода?
Оракул док о Wildcards в дженериках говорит,
Подстановочный знак может использоваться в различных ситуациях: в качестве типа параметра, поля или локальной переменной; иногда в качестве возвращаемого типа (хотя лучше программировать, чтобы быть более конкретным).
Я попробовал все четыре в следующем классе, и получил ошибки компилятора на каждом. Зачем? Что я делаю неправильно?
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 ответа
Учебник ужасно сформулирован. Вы не можете использовать подстановочный знак для любой из перечисленных вещей. Для этих целей вы можете использовать универсальный тип с подстановочным знаком.
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
}
}
?
символ - это аргумент типа шаблона.
Статья начинается с
В общем коде знак вопроса (?), Называемый подстановочным знаком, представляет неизвестный тип.
Единственное место, где вы можете использовать этот синтаксис, является частью общего кода, т.е. аргумент универсального типа. Следующее предложение относится к общему коду с использованием подстановочного знака. Так, например
как тип параметра
ты мог бы иметь
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 */}
Подстановочный знак может использоваться с оператором<> в общей концепции, представленной в 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;
}
Подстановочные знаки не имеют индивидуального существования. Они всегда используются в качестве параметра типа общих классов 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));
}
}