public class UnboundedWildcards2 { static Map mapl; static Map map2; static Map map3; static void assignlCMap map) { mapl = map; } static void assign2(Map map) { map2 = map; } static void assign3(Map map) { map3 = map; } public static void main(String[] args) { assignl(new HashMapO); assign2(new HashMapO); // assign3(new HashMapO); // Предупреждение: // Непроверенное преобразование. Обнаружен: HashMap // Требуется: Map assignl(new HashMap()); assign2(new HashMap()); assign3(new HashMap0):

}

} ///-

Когда в записи используются только неограниченные метасимволы, как в примере Мар, компилятор не отличает такой тип от Map. Кроме того, пример UnboundedWildcardsl.java показывает, что компилятор по-разному интерпретирует List и List.

Ситуация осложняется тем, что компилятор не всегда интересуется различиями между List и List (например), поэтому может показаться, что это одно и то же. В самом деле, поскольку параметризованный аргумент стирается до первого ограничения, List кажется эквивалентным List, a List, по сути, тоже является List — однако ни одно из этих утверждений не является в полной мере истинным. List в действительности означает «низкоуровневый List, содержащий любой тип Object», тогда как List означает «не-низкоуровне-вый List, содержащий какой-то конкретный тип, хотя мы не знаем, какой именно».

Когда же компилятор различает низкоуровневые типы и типы с неограниченными метасимволами? В следующем примере используется класс Holder, определение которого приводилось ранее. Класс содержит методы, получающие аргумент Holder, но в разных формах: в виде низкоуровневого типа, с конкретным параметром типа, с неограниченным метасимволом:

//: generics/Wildcards.java // Exploring the meaning of wildcards.

public class Wildcards {

// Низкоуровневый аргумент: static void rawArgs(Holder holder. Object arg) { // holder set(arg); // Предупреждение-// Непроверенный вызов set(T) как члена // низкоуровневого типа Holder // holder, set (new WildcardsO); // To же предупреждение

// Невозможно: нет информации о 'Т' // T t = holder.getO.

// Допустимо, но информация типа теряется Object obj = holder getO.

}

// По аналогии с rawArgsO, но ошибки вместо предупреждений, static void unboundedArg(Holder holder. Object arg) { // holder.set(arg); // Ошибка: // set(capture of ?) in Holder // не может применяться к (Object) // holder, set (new WildcardsO). // Та же ошибка

// Невозможно; нет информации о 'Т': // T t = holder.get();

// Допустимо, но информация типа теряется: Object obj = holder.getO;

}

static T exactl(Holder holder) { T t = holder.getO; return t;

}

static T exact2(Holder holder. T arg) { holder.set(arg); T t = holder.getO; return t;

}

static

T wildSubtype(Holder holder. T arg) { // holder.set(arg); // Ошибка: // set(capture of ? extends T) in // Holder // cannot be applied to (T) T t = holder.getO; return t;

}

static

void wildSupertype(Holder holder, T arg) { holder.set(arg);

// T t = holder.getO; // Ошибка:

// Несовместимые типы: обнаружен Object, требуется T

// Допустимо, но информация типа теряется: Object obj = holder get О;

}

public static void main(String[] args) {

Holder raw = new Holder(). // Или

raw = new Holder(),

Holder qualified = new Holder(), Holder unbounded = new Holder(). Holder<? extends Long> bounded = new Holder(), Long Ing = 1L;

rawArgs(raw. Ing), rawArgs(qualified, Ing), rawArgs(unbounded. 1ng). rawArgs(bounded, Ing);

unboundedArg(raw, Ing), unboundedArg(qualified, Ing), unboundedArg(unbounded, Ing), unboundedArg(bounded, Ing),

Перейти на страницу:

Похожие книги