Π§ΠΈΡ‚Π°ΠΉΡ‚Π΅ ΠΊΠ½ΠΈΠ³ΠΈ ΠΎΠ½Π»Π°ΠΉΠ½ Π½Π° Bookidrom.ru! БСсплатныС ΠΊΠ½ΠΈΠ³ΠΈ Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΊΠ»ΠΈΠΊΠ΅

Π§ΠΈΡ‚Π°Ρ‚ΡŒ ΠΎΠ½Π»Π°ΠΉΠ½ «Ѐилософия Java3Β». Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Π° 91

Автор Π‘Ρ€ΡŽΡ ЭккСль

// Ошибка компиляции: нСсовмСстимыС Ρ‚ΠΈΠΏΡ‹ List<Fruit> flist = new ArrayList<Apple>(); } ///:-

На ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ взгляд это выглядит ΠΊΠ°ΠΊ ΡƒΡ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΈΠ΅ Β«ΠšΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ с элСмСнтами Apple нСльзя ΠΏΡ€ΠΈΡΠ²ΠΎΠΈΡ‚ΡŒ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Ρƒ с элСмСнтами FruitΒ», Π½ΠΎ слСдуСт Π²ΡΠΏΠΎΠΌΠ½ΠΈΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ парамСтризация β€” это Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Ρ‹. Π’ Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ ΡƒΡ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΈΠ΅ слСдуСт Ρ‚Ρ€Π°ΠΊΡ‚ΠΎΠ²Π°Ρ‚ΡŒ ΡˆΠΈΡ€Π΅: Β«ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΠ·ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ задСйствован Ρ‚ΠΈΠΏ Apple, нСльзя ΠΏΡ€ΠΈΡΠ²ΠΎΠΈΡ‚ΡŒ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΠ·ΠΎΠ²Π°Π½Π½ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ задСйствован Ρ‚ΠΈΠΏ FruitΒ». Если Π±Ρ‹, ΠΊΠ°ΠΊ Π² случаС с массивами, компилятор располагал достаточной ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠ΅ΠΉ ΠΈ ΠΌΠΎΠ³ ΠΏΠΎΠ½ΡΡ‚ΡŒ, Ρ‡Ρ‚ΠΎ Ρ€Π΅Ρ‡ΡŒ ΠΈΠ΄Π΅Ρ‚ ΠΎ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°Ρ…, ΠΎΠ½ ΠΌΠΎΠ³ Π±Ρ‹ ΠΏΡ€ΠΎΡΠ²ΠΈΡ‚ΡŒ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ ΡΠ½ΠΈΡΡ…ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ. Но компилятор Ρ‚Π°ΠΊΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠ΅ΠΉ Π½Π΅ располагаСт, поэтому ΠΎΠ½ отказываСтся Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ «восходящСС ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅Β». Π’ΠΏΡ€ΠΎΡ‡Π΅ΠΌ, это ΠΈ Π½Π΅ являСтся восходящим ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ β€” List с элСмСнтами Apple Π½Π΅ являСтся «частным случаСм» List с элСмСнтами Fruit. ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ ΠΌΠΎΠΆΠ΅Ρ‚ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Apple ΠΈ ΠΏΠΎΠ΄Ρ‚ΠΈΠΏΡ‹ Apple, Π° Π²Ρ‚ΠΎΡ€ΠΎΠΉ β€” Π»ΡŽΠ±Ρ‹Π΅ разновидности Fruit... Π΄Π°, Π² Ρ‚ΠΎΠΌ числС ΠΈ Apple, Π½ΠΎ ΠΎΡ‚ этого ΠΎΠ½ Π½Π΅ становится List с элСмСнтами Apple, Π° ΠΏΠΎ-ΠΏΡ€Π΅ΠΆΠ½Π΅ΠΌΡƒ остаСтся List с элСмСнтами Fruit.

ΠŸΡ€ΠΎΠ±Π»Π΅ΠΌΠ° Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Ρ€Π΅Ρ‡ΡŒ ΠΈΠ΄Π΅Ρ‚ ΠΎ Ρ‚ΠΈΠΏΠ΅ ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π°, Π° Π½Π΅ ΠΎ Ρ‚ΠΈΠΏΠ΅ элСмСнтов, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π² этом ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€Π΅ хранятся. Π’ ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ массивов, ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΠ·ΠΎΠ²Π°Π½Π½Ρ‹Π΅ Ρ‚ΠΈΠΏΡ‹ Π½Π΅ ΠΎΠ±Π»Π°Π΄Π°ΡŽΡ‚ встроСнной ΠΊΠΎΠ²Π°Ρ€ΠΈΠ°Π½Ρ‚Π½ΠΎΡΡ‚ΡŒΡŽ. Π­Ρ‚ΠΎ связано с Ρ‚Π΅ΠΌ, Ρ‡Ρ‚ΠΎ массивы ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚ΡΡ Π² языкС ΠΈ для Π½ΠΈΡ… ΠΌΠΎΠ³ΡƒΡ‚ Π±Ρ‹Ρ‚ΡŒ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Ρ‹ встроСнныС ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ ΠΊΠ°ΠΊ Π²ΠΎ врСмя компиляции, Ρ‚Π°ΠΊ ΠΈ Π²ΠΎ врСмя выполнСния, Π½ΠΎ с ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΠ·ΠΎΠ²Π°Π½Π½Ρ‹ΠΌΠΈ Ρ‚ΠΈΠΏΠ°ΠΌΠΈ компилятор ΠΈ систСма Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ выполнСния Π½Π΅ Π·Π½Π°ΡŽΡ‚, Ρ‡Ρ‚ΠΎ Π²Ρ‹ ΡΠΎΠ±ΠΈΡ€Π°Π΅Ρ‚Π΅ΡΡŒ Π΄Π΅Π»Π°Ρ‚ΡŒ с Ρ‚ΠΈΠΏΠ°ΠΌΠΈ ΠΈ ΠΊΠ°ΠΊΠΈΠ΅ ΠΏΡ€Π°Π²ΠΈΠ»Π° ΠΏΡ€ΠΈ этом Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Π΄Π΅ΠΉΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ.

Но ΠΈΠ½ΠΎΠ³Π΄Π° ΠΌΠ΅ΠΆΠ΄Ρƒ двумя разновидностями ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΠ·ΠΎΠ²Π°Π½Π½Ρ‹Ρ… Ρ‚ΠΈΠΏΠΎΠ² всС ΠΆΠ΅ трСбуСтся ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ связь, Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½ΡƒΡŽ восходящСму ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΡŽ. ИмСнно это ΠΈ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ мСтасимволы.

//: generics/GenericsAndCovariance.java

import java.util.*;

public class GenericsAndCovariance {

public static void main(String[] args) {

// ΠœΠ΅Ρ‚Π°ΡΠΈΠΌΠ²ΠΎΠ»Ρ‹ ΠΎΠ±Π΅ΡΠΏΠ΅Ρ‡ΠΈΠ²Π°ΡŽΡ‚ ΠΊΠΎΠ²Π°Ρ€ΠΈΠ°Π½Ρ‚Π½ΠΎΡΡ‚ΡŒ:

List<? extends Fruit> flist = new ArrayList<Apple>();

// Ошибка компиляции: Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°

// ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ»ΡŒΠ½ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ° Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ

// flist.add(new AppleO);

// flist.add(new FruitO);

// flist.add(new ObjectO);

flist.add(null); // МоТно, Π½ΠΎ нСинтСрСсно

// ΠœΡ‹ Π·Π½Π°Π΅ΠΌ, Ρ‡Ρ‚ΠΎ возвращаСтся ΠΏΠΎ ΠΊΡ€Π°ΠΉΠ½Π΅ΠΉ ΠΌΠ΅Ρ€Π΅ Fruit:

Fruit f = flist.get(O);

}

} ///:-

Π’Π΅ΠΏΠ΅Ρ€ΡŒ flist относится ΠΊ Ρ‚ΠΈΠΏΡƒ List<? extends Fruit>, Ρ‡Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΊΠ°ΠΊ «список с элСмСнтами любого Ρ‚ΠΈΠΏΠ°, ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΎΡ‚ FruitΒ». Однако Π² Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ это Π½Π΅ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ List Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ ΠΈΠΌΠ΅Π½Π½ΠΎ Ρ‚ΠΈΠΏΡ‹ ΠΈΠ· сСмСйства Fruit. ΠœΠ΅Ρ‚Π°ΡΠΈΠΌΠ²ΠΎΠ» ΠΎΠ±ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ Β«Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ, Π½Π΅ ΡƒΠΊΠ°Π·Π°Π½Π½Ρ‹ΠΉ Π² ссылкС flistΒ». Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, присваиваСмый List Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠΎΠ΄Π΅Ρ€ΠΆΠ°Ρ‚ΡŒ Π½Π΅ΠΊΠΈΠΉ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Fruit ΠΈΠ»ΠΈ Apple), Π½ΠΎ для восходящСго прСобразования ΠΊ flist этот Ρ‚ΠΈΠΏ нСсущСствСнСн.

Если СдинствСнноС ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅ состоит Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ List содСрТит Fruit ΠΈΠ»ΠΈ ΠΎΠ΄ΠΈΠ½ ΠΈΠ· Π΅Π³ΠΎ ΠΏΠΎΠ΄Ρ‚ΠΈΠΏΠΎΠ², Π½ΠΎ вас Π½Π΅ интСрСсуСт, ΠΊΠ°ΠΊΠΎΠΉ ΠΈΠΌΠ΅Π½Π½ΠΎ, Ρ‡Ρ‚ΠΎ ΠΆΠ΅ с Π½ΠΈΠΌ ΠΌΠΎΠΆΠ½ΠΎ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ? Если Π²Ρ‹ Π½Π΅ Π·Π½Π°Π΅Ρ‚Π΅, ΠΊΠ°ΠΊΠΈΠ΅ Ρ‚ΠΈΠΏΡ‹ хранятся Π² List, Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ Π»ΠΈ бСзопасноС Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π°? НСт, ΠΊΠ°ΠΊ ΠΈ Π² случаС с CovariantArrays.java, Π½ΠΎ Π½Π° этот Ρ€Π°Π· ошибка выявляСтся компилятором, Π° Π½Π΅ систСмой Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ выполнСния.

ΠœΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠΊΠ°Π·Π°Ρ‚ΡŒΡΡ, Ρ‡Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ Π½Π΅ совсСм Π»ΠΎΠ³ΠΈΡ‡Π΅Π½ β€” Π²Π°ΠΌ Π½Π΅ удастся Π΄Π°ΠΆΠ΅ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Apple Π² List, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ, ΠΊΠ°ΠΊ Π²Ρ‹ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‡Ρ‚ΠΎ ΡƒΠΊΠ°Π·Π°Π»ΠΈ, Π΄ΠΎΠ»ΠΆΠ½Ρ‹ Ρ…Ρ€Π°Π½ΠΈΡ‚ΡŒΡΡ Apple. Π”Π°, ΠΊΠΎΠ½Π΅Ρ‡Π½ΠΎ, Π½ΠΎ компилятор-Ρ‚ΠΎ этого Π½Π΅ Π·Π½Π°Π΅Ρ‚! List<? extends Fruit> Π²ΠΏΠΎΠ»Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Π½Π° List<Orange>.

Π‘ Π΄Ρ€ΡƒΠ³ΠΎΠΉ стороны, Π²Ρ‹Π·ΠΎΠ² ΠΌΠ΅Ρ‚ΠΎΠ΄Π°, Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡŽΡ‰Π΅Π³ΠΎ Fruit, бСзопасСн; ΠΌΡ‹ Π·Π½Π°Π΅ΠΌ, Ρ‡Ρ‚ΠΎ всС элСмСнты List Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΏΠΎ мСньшСй ΠΌΠ΅Ρ€Π΅ ΠΎΡ‚Π½ΠΎΡΠΈΡ‚ΡŒΡΡ ΠΊ Fruit, поэтому компилятор это ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ‚.

Насколько ΡƒΠΌΠ΅Π½ компилятор?

Казалось Π±Ρ‹, ΠΈΠ· всСго сказанного слСдуСт, Ρ‡Ρ‚ΠΎ Π²Ρ‹Π·ΠΎΠ² Π»ΡŽΠ±Ρ‹Ρ… ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² с Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°ΠΌΠΈ Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ΅Π½, Π½ΠΎ рассмотрим ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ ΠΏΡ€ΠΈΠΌΠ΅Ρ€:

//: generics/Compi1erIntel 1 igence.java

import java.util .*;

public class Compilerlntelligence {

public static void main(String[] args) { List<? extends Fruit> flist =

Arrays.asList(new AppleO); Apple a = (Apple)flist.get(O); // Π‘Π΅Π· ΠΏΡ€Π΅Π΄ΡƒΠΏΡ€Π΅ΠΆΠ΄Π΅Π½ΠΈΠΉ fli st. contains (new AppleO); //АргумСнт 'Object' fl i st. indexOf (new AppleO); //АргумСнт 'Object'

}

} ///:-

Как Π²ΠΈΠ΄ΠΈΡ‚Π΅, Π²Ρ‹Π·ΠΎΠ²Ρ‹ contains() ΠΈ indexOf() с Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°ΠΌΠΈ Apple Π²ΠΎΡΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°ΡŽΡ‚ΡΡ Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½ΠΎ. ΠžΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ Π»ΠΈ это, Ρ‡Ρ‚ΠΎ компилятор Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΊΠΎΠ΄, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ·Π½Π°Ρ‚ΡŒ, ΠΌΠΎΠ΄ΠΈΡ„ΠΈΡ†ΠΈΡ€ΡƒΠ΅Ρ‚ Π»ΠΈ Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ свой ΠΎΠ±ΡŠΠ΅ΠΊΡ‚?

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ ArrayList ΠΏΠΎΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ компилятор Π½Π΅ Π½Π°ΡΡ‚ΠΎΠ»ΡŒΠΊΠΎ ΡƒΠΌΠ΅Π½. Если add() ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΠ·ΡƒΡŽΡ‰Π΅Π³ΠΎ Ρ‚ΠΈΠΏΠ°, contains() ΠΈ in-dexOf() ΠΏΠΎΠ»ΡƒΡ‡Π°ΡŽΡ‚ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ Ρ‚ΠΈΠΏΠ° Object. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, ΠΊΠΎΠ³Π΄Π° Π²Ρ‹ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅Ρ‚Π΅ ArrayList<? extends Fruit>, Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ add() прСвращаСтся Π² Β«? extends FruitΒ». По этому описанию компилятор Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ, ΠΊΠ°ΠΊΠΎΠΉ ΠΈΠΌΠ΅Π½Π½ΠΎ ΠΏΠΎΠ΄Ρ‚ΠΈΠΏ Fruit трСбуСтся Π² Π΄Π°Π½Π½ΠΎΠΌ случаС, поэтому Π½Π΅ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π½ΠΈΠΊΠ°ΠΊΠΈΠ΅ Ρ‚ΠΈΠΏΡ‹ Fruit. Π”Π°ΠΆΠ΅ Ссли Π²Ρ‹ ΠΏΡ€Π΅Π΄Π²Π°Ρ€ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΡƒΠ΅Ρ‚Π΅ Apple Π² Fruit, компилятор всС Ρ€Π°Π²Π½ΠΎ откаТСтся Π²Ρ‹Π·Ρ‹Π²Π°Ρ‚ΡŒ ΠΌΠ΅Ρ‚ΠΎΠ΄ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, add()), Ссли Π² спискС Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² присутствуСт мСтасимвол.

Π£ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² contains() ΠΈ indexOf() Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ относятся ΠΊ Ρ‚ΠΈΠΏΡƒ Object, мСтасимволы Π² Π½ΠΈΡ… ΠΎΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‚, поэтому компилятор Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ Π²Ρ‹Π·ΠΎΠ². Π­Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΈΡ€ΠΎΠ²Ρ‰ΠΈΠΊ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΠ·ΠΎΠ²Π°Π½Π½ΠΎΠ³ΠΎ класса Π΄ΠΎΠ»ΠΆΠ΅Π½ сам Ρ€Π΅ΡˆΠΈΡ‚ΡŒ, ΠΊΠ°ΠΊΠΈΠ΅ Π²Ρ‹Π·ΠΎΠ²Ρ‹ «бСзопасны», ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚ΠΈΠΏΡ‹ Object для ΠΈΡ… Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ². Π§Ρ‚ΠΎΠ±Ρ‹ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½Ρ‹ΠΌ Π²Ρ‹Π·ΠΎΠ² ΠΏΡ€ΠΈ использовании Ρ‚ΠΈΠΏΠ° с мСтасимволами, Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ Ρ‚ΠΈΠΏΠ° Π² список Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ².

Π’ качСствС ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° рассмотрим ΠΎΡ‡Π΅Π½ΡŒ простой класс Holder:

//: generics/Holder.java

public class Holder<T> { private T value; public HolderO {}

public Holder(T val) { value = val; } public void set(T val) { value = val; } public T getО { return value; } public boolean equals(Object obj) { return value.equals(obj);

}

public static void main(String[] args) {

Holder<Apple> Apple = new Holder<Apple>(new AppleO); Apple d = Apple.getO; Apple.set(d);

// Holder<Fruit> Fruit = Apple; // ΠŸΠΎΠ²Ρ‹ΡˆΠ΅Π½ΠΈΠ΅ Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ Holder<? extends Fruit> fruit = Apple; // OK Fruit p = fruit.getO;

d = (Apple)fruit.getO; // Π’ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ 'Object' try {

Orange с = (Orange)fruit.getO; // ΠŸΡ€Π΅Π΄ΡƒΠΏΡ€Π΅ΠΆΠ΄Π΅Π½ΠΈΡ Π½Π΅Ρ‚ } catch(Exception e) { System.out.println(e); } // fruit.set(new AppleO); // Π’Ρ‹Π·ΠΎΠ² setO Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ΅Π½ // fruit.set(new FruitO); // Π’Ρ‹Π·ΠΎΠ² setO Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ΅Π½ System.out.println(fruit.equals(d)); // OK

}

} /* Output: (Sample)

java.lang.ClassCastException. Apple cannot be cast to Orange

true

*///:-

Holder содСрТит ΠΌΠ΅Ρ‚ΠΎΠ΄ set(), ΠΏΠΎΠ»ΡƒΡ‡Π°ΡŽΡ‰ΠΈΠΉ T; ΠΌΠ΅Ρ‚ΠΎΠ΄ get(), Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°ΡŽΡ‰ΠΈΠΉ Π’; ΠΈ ΠΌΠ΅Ρ‚ΠΎΠ΄ equals(), ΠΏΠΎΠ»ΡƒΡ‡Π°ΡŽΡ‰ΠΈΠΉ Object. Как Π²Ρ‹ ΡƒΠΆΠ΅ Π²ΠΈΠ΄Π΅Π»ΠΈ, Holder<Apple> Π½Π΅Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Ρ‚ΡŒ Π² Holder<Fruit>, Π½ΠΎ Π·Π°Ρ‚ΠΎ ΠΌΠΎΠΆΠ½ΠΎ Π² Holder<? extends Fruit>. ΠŸΡ€ΠΈ Π²Ρ‹Π·ΠΎΠ²Π΅ get() Π±ΡƒΠ΄Π΅Ρ‚ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π΅Π½ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‚ΠΈΠΏ Fruit β€” Ρ‚ΠΎ, Ρ‡Ρ‚ΠΎ извСстно компилятору ΠΏΠΎ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΡŽ «всС, Ρ‡Ρ‚ΠΎ Ρ€Π°ΡΡˆΠΈΡ€ΡΠ΅Ρ‚ FruitΒ». Если Π²Ρ‹ располагаСтС Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠ΅ΠΉ, Ρ‚ΠΎ смоТСтС Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΊ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ Fruit ΠΈ ΠΎΠ±ΠΎΠΉΡ‚ΠΈΡΡŒ Π±Π΅Π· ΠΏΡ€Π΅Π΄ΡƒΠΏΡ€Π΅ΠΆΠ΄Π΅Π½ΠΈΠΉ, Π½ΠΎ с риском ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ ClassCastException. ΠœΠ΅Ρ‚ΠΎΠ΄ set() Π½Π΅ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π½ΠΈ с Apple, Π½ΠΈ с Fruit, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ set() Ρ‚ΠΎΠΆΠ΅ содСрТит Β«? extends FruitΒ»; ΠΏΠΎ сути, ΠΎΠ½ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Ρ‡Π΅ΠΌ ΡƒΠ³ΠΎΠ΄Π½ΠΎ, Π° компилятор Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡ‚ΡŒ Ρ‚ΠΈΠΏΠΎΠ² для Β«Ρ‡Π΅Π³ΠΎ ΡƒΠ³ΠΎΠ΄Π½ΠΎΒ».

Π’ΠΏΡ€ΠΎΡ‡Π΅ΠΌ, ΠΌΠ΅Ρ‚ΠΎΠ΄ equalsQ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ Π½ΠΎΡ€ΠΌΠ°Π»ΡŒΠ½ΠΎ, ΠΏΠΎΡ‚ΠΎΠΌΡƒ Ρ‡Ρ‚ΠΎ ΠΎΠ½ ΠΏΠΎΠ»ΡƒΡ‡Π°Π΅Ρ‚ Object вмСсто Π’. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, компилятор ΠΎΠ±Ρ€Π°Ρ‰Π°Π΅Ρ‚ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Π½Π° Ρ‚ΠΈΠΏΡ‹ ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Π΅ΠΌΡ‹Ρ… ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅ΠΌΡ‹Ρ… ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ². Он Π½Π΅ Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΊΠΎΠ΄, провСряя, Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ΡΡ Π»ΠΈ Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ чтСния ΠΈΠ»ΠΈ записи.

ΠšΠΎΠ½Ρ‚Ρ€Π°Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Π½ΠΎΡΡ‚ΡŒ

Π’Π°ΠΊΠΆΠ΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠΉΡ‚ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠΌ ΠΏΡƒΡ‚Π΅ΠΌ ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ мСтасимволы супСртипов. Π’ этом случаС Π²Ρ‹ сообщаСтС, Ρ‡Ρ‚ΠΎ мСтасимвол ограничиваСтся Π±Π°Π·ΠΎΠ²Ρ‹ΠΌ классом Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ класса; ΠΏΡ€ΠΈ этом ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ запись <? super MyClass>, ΠΈ Π΄Π°ΠΆΠ΅ с ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠΌ Ρ‚ΠΈΠΏΠ° <? super Π’>. Π­Ρ‚ΠΎ позволяСт бСзопасно ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒ Ρ‚ΠΈΠΏΠΈΠ·ΠΎΠ²Π°Π½Π½Ρ‹ΠΉ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΈΠ·ΠΎΠ²Π°Π½Π½ΠΎΠΌΡƒ Ρ‚ΠΈΠΏΡƒ. Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, с использованиСм мСтасимволов супСртипов становится Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎΠΉ запись Π² ΠΊΠΎΠ»Π»Π΅ΠΊΡ†ΠΈΡŽ:

//β€’ generics/SuperTypeWiIdcards java

import java util.*:

public class SuperTypeWiIdcards {

static void writeTo(List<? super Apple> apples) { apples add(new AppleO), apples add(new JonathanO); // apples.add(new FruitO); // Ошибка

}

} /// ~

АргумСнт apples являСтся ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€ΠΎΠΌ List для Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Ρ‚ΠΈΠΏΠ°, ΡΠ²Π»ΡΡŽΡ‰Π΅Π³ΠΎΡΡ Π±Π°Π·ΠΎΠ²Ρ‹ΠΌ для Apple; ΠΈΠ· этого слСдуСт, Ρ‡Ρ‚ΠΎ Apple ΠΈ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄Π½Ρ‹Π΅ ΠΎΡ‚ Apple Ρ‚ΠΈΠΏΡ‹ ΠΌΠΎΠ³ΡƒΡ‚ бСзопасно Π²ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒΡΡ Π² ΠΊΠΎΠ½Ρ‚Π΅ΠΉΠ½Π΅Ρ€. Но, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ Π½ΠΈΠΆΠ½ΠΈΠΌ ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅ΠΌ являСтся Apple, ΠΌΡ‹ Π½Π΅ Π·Π½Π°Π΅ΠΌ, бСзопасно Π»ΠΈ Π²ΠΊΠ»ΡŽΡ‡Π°Ρ‚ΡŒ Fruit Π² Ρ‚Π°ΠΊΠΎΠΉ List, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ это ΠΎΡ‚ΠΊΡ€ΠΎΠ΅Ρ‚ List для добавлСния Ρ‚ΠΈΠΏΠΎΠ², ΠΎΡ‚Π»ΠΈΡ‡Π½Ρ‹Ρ… ΠΎΡ‚ Apple, с Π½Π°Ρ€ΡƒΡˆΠ΅Π½ΠΈΠ΅ΠΌ статичСской бСзопасности Ρ‚ΠΈΠΏΠΎΠ².

ΠžΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΡ супСртипов Ρ€Π°ΡΡˆΠΈΡ€ΡΡŽΡ‚ возмоТности ΠΏΠΎ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Π΅ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² ΠΌΠ΅Ρ‚ΠΎΠ΄Ρƒ:

//. generics/GenericWriting.java

import java.util.*;

public class GenericWriting {

static <T> void writeExact(List<T> list. T item) { list.add(item),

}

static List<Apple> apples = new ArrayList<Apple>();

static List<Fruit> fruit = new ArrayList<Fruit>();

static void flO {

writeExact(apples, new AppleO);

// writeExact(fruit, new AppleO); // Ошибка:

// НСсовмСстимыС Ρ‚ΠΈΠΏΡ‹: ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠ΅Π½ Fruit, трСбуСтся Apple

}

static <T> void

writeWithWildcard(List<? super T> list, T item) { list.add(item);

}

static void f20 {

writeWithWildcard(apples, new AppleO); writeWithWildcard(fruit, new AppleO);

}

public static void main(String[] args) { flO, f2(); }

} ///.-

ΠœΠ΅Ρ‚ΠΎΠ΄ writeExact() ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ Ρ‚ΠΈΠΏΠ° Β«ΠΊΠ°ΠΊ Π΅ΡΡ‚ΡŒΒ», Π±Π΅Π· мСтасимволов. На ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ fl() ΠΌΡ‹ Π²ΠΈΠ΄ΠΈΠΌ, Ρ‡Ρ‚ΠΎ этот способ ΠΎΡ‚Π»ΠΈΡ‡Π½ΠΎ Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ β€” ΠΏΡ€ΠΈ условии, Ρ‡Ρ‚ΠΎ Π² List<Apple> ΠΏΠΎΠΌΠ΅Ρ‰Π°ΡŽΡ‚ΡΡ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ Apple. Однако writeExact() Π½Π΅ позволяСт ΠΏΠΎΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ Apple Π² List<Fruit>, хотя ΠΌΡ‹ Π·Π½Π°Π΅ΠΌ, Ρ‡Ρ‚ΠΎ это Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ.

Π’ writeWithWildcard() ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ List<? super Π’>, поэтому List содСрТит ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹ΠΉ Ρ‚ΠΈΠΏ, ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄Π½Ρ‹ΠΉ ΠΎΡ‚ Π’; ΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ, Π’ ΠΈΠ»ΠΈ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄Π½Ρ‹Π΅ ΠΎΡ‚ Π½Π΅Π³ΠΎ Ρ‚ΠΈΠΏΡ‹ ΠΌΠΎΠ³ΡƒΡ‚ бСзопасно ΠΏΠ΅Ρ€Π΅Π΄Π°Π²Π°Ρ‚ΡŒΡΡ Π² Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ² List. ΠŸΡ€ΠΈΠΌΠ΅Ρ€ встрСчаСтся Π² f2: ΠΊΠ°ΠΊ ΠΈ ΠΏΡ€Π΅ΠΆΠ΄Π΅, Apple ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ Π² List<Apple>, Π½ΠΎ, ΠΊΠ°ΠΊ ΠΈ ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»Π°Π³Π°Π»ΠΎΡΡŒ, Ρ‚Π°ΠΊΠΆΠ΅ стало ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ Apple Π² List<Fruit>.