Васильев А.Н. Основы программирования на C#. Васильев А. Н. Программирование
Скачать 5.54 Mb.
|
Листинг 7.2. Несколько обобщенных параметров System; // Ƚɥɚɜɧɵɣ ɤɥɚɫɫ: class MoreGenMethDemo{ // Ɇɟɬɨɞ ɫ ɞɜɭɦɹ ɨɛɨɛɳɟɧɧɵɦɢ ɩɚɪɚɦɟɬɪɚɦɢ: static void show // Ɉɬɨɛɪɚɠɟɧɢɟ ɡɧɚɱɟɧɢɣ ɚɪɝɭɦɟɧɬɨɜ: Console.WriteLine( Ǝɉɟɪɜɵɣ ɚɪɝɭɦɟɧɬ {0}Ǝ,a); Console.WriteLine( Ǝȼɬɨɪɨɣ ɚɪɝɭɦɟɧɬ {0}Ǝ,b); } // Ƚɥɚɜɧɵɣ ɦɟɬɨɞ: static void Main(){ // ȼɵɡɨɜ ɨɛɨɛɳɟɧɧɨɝɨ ɦɟɬɨɞɚ: show(100, ƍAƍ); show( ƍBƍ,ƎBravoƎ); show( ƍCƍ,ƍDƍ); show ƍCƍ,ƍDƍ); } } Обобщенные типы 337 Результат выполнения программы такой, как показано ниже: Результат выполнения программы (из листинга 7.2) ɉɟɪɜɵɣ ɚɪɝɭɦɟɧɬ 100 ȼɬɨɪɨɣ ɚɪɝɭɦɟɧɬ A ɉɟɪɜɵɣ ɚɪɝɭɦɟɧɬ B ȼɬɨɪɨɣ ɚɪɝɭɦɟɧɬ Bravo ɉɟɪɜɵɣ ɚɪɝɭɦɟɧɬ C ȼɬɨɪɨɣ ɚɪɝɭɦɟɧɬ D ɉɟɪɜɵɣ ɚɪɝɭɦɟɧɬ 67 ȼɬɨɪɨɣ ɚɪɝɭɦɟɧɬ Принципы описания и использования методов с несколькими обобщенными параметрами точно такие, как ив случае с методами, имеющими один параметр. Просто нужно сделать поправку на то, что параметров теперь несколько. Схема использования обобщенных методов не сводится лишь к передаче методам параметров разных типов. Скажем, аргументом метода может быть массив из элементов обобщенного типа или метод может подобный массив возвращать как результат. Небольшая зарисовка к сказанному представлена в программе в листинге Листинг 7.3. Различные обобщенные методы System; // Ʉɥɚɫɫ ɫ ɝɥɚɜɧɵɦ ɦɟɬɨɞɨɦ: class MuchMoreGenMethDemo{ // Ɉɛɨɛɳɟɧɧɵɣ ɦɟɬɨɞ ɫ ɚɪɝɭɦɟɧɬɨɦ - ɦɚɫɫɢɜɨɦ ɢɡ // ɷɥɟɦɟɧɬɨɜ ɨɛɨɛɳɟɧɧɨɝɨ ɬɢɩɚ: static void show // Ɉɬɨɛɪɚɠɟɧɢɟ ɡɧɚɱɟɧɢɣ ɷɥɟɦɟɧɬɨɜ ɦɚɫɫɢɜɚ: for(int k=0;k Ǝ|Ǝ+array[k]); } Console.WriteLine( Ǝ|Ǝ); } Глава 7 338 // Ɉɛɨɛɳɟɧɧɵɣ ɦɟɬɨɞ ɜɨɡɜɪɚɳɚɟɬ ɪɟɡɭɥɶɬɚɬɨɦ ɦɚɫɫɢɜ ɢɡ // ɷɥɟɦɟɧɬɨɜ ɨɛɨɛɳɟɧɧɨɝɨ ɬɢɩɚ: static T[] create // ɋɨɡɞɚɧɢɟ ɦɚɫɫɢɜɚ ɢɡ ɷɥɟɦɟɧɬɨɜ ɨɛɨɛɳɟɧɧɨɝɨ ɬɢɩɚ: T[] array=new T[n]; // Ɋɟɡɭɥɶɬɚɬ ɦɟɬɨɞɚ - ɫɫɵɥɤɚ ɧɚ ɦɚɫɫɢɜ: return array; } // Ɉɛɨɛɳɟɧɧɵɣ ɦɟɬɨɞ ɞɥɹ ɡɚɩɨɥɧɟɧɢɹ ɦɚɫɫɢɜɚ ɡɧɚɱɟɧɢɹɦɢ: static void fill // ɉɟɪɟɛɢɪɚɸɬɫɹ ɷɥɟɦɟɧɬɵ ɦɚɫɫɢɜɚ: for(int k=0;k ɗɥɟɦɟɧɬɭ ɦɚɫɫɢɜɚ ɩɪɢɫɜɚɢɜɚɟɬɫɹ ɡɧɚɱɟɧɢɟ: a[k]=b; } } // Ɉɛɨɛɳɟɧɧɵɣ ɦɟɬɨɞ ɪɟɡɭɥɶɬɚɬɨɦ ɜɨɡɜɪɚɳɚɟɬ ɡɧɚɱɟɧɢɟ // ɫɥɭɱɚɣɧɨɝɨ ɷɥɟɦɟɧɬɚ ɢɡ ɦɚɫɫɢɜɚ: static T getRand // Ɋɟɡɭɥɶɬɚɬ ɦɟɬɨɞɚ: return a[rnd.Next(a.Length)]; } // Ƚɥɚɜɧɵɣ ɦɟɬɨɞ: static void Main(){ // ɋɨɡɞɚɧɢɟ ɨɛɴɟɤɬɚ ɞɥɹ ɝɟɧɟɪɢɪɨɜɚɧɢɹ ɱɢɫɟɥ: Random rnd=new Random(); // ɋɨɡɞɚɧɢɟ ɦɚɫɫɢɜɨɜ: string[] A={ ƎoneƎ,ƎtwoƎ,ƎthreeƎ}; int[] B={2,3,5,8,13,21}; char[] C={ ƍcƍ,ƍhƍ,ƍaƍ,ƍrƍ,ƍlƍ,ƍiƍ}; // ȼɵɡɨɜ ɨɛɨɛɳɟɧɧɵɯ ɦɟɬɨɞɨɜ: show(A); Обобщенные типы show(B); Console.WriteLine( Ǝɋɥɭɱɚɣɧɵɟ ɱɢɫɥɚ:Ǝ); for(int k=1;k<=10;k++){ Console.Write(getRand(B,rnd)+ Ǝ Ǝ); } Console.WriteLine(); show(C); Console.WriteLine( Ǝɋɥɭɱɚɣɧɵɟ ɫɢɦɜɨɥɵ:Ǝ); for(int k=1;k<=10;k++){ Console.Write(getRand(C,rnd)+ Ǝ Ǝ); } Console.WriteLine(); // ɋɨɡɞɚɧɢɟ ɫɢɦɜɨɥɶɧɨɝɨ ɦɚɫɫɢɜɚ ɜɵɡɨɜɨɦ ɦɟɬɨɞɚ: char[] symbs=create // Ɂɚɩɨɥɧɟɧɢɟ ɦɚɫɫɢɜɚ ɫɢɦɜɨɥɚɦɢ: fill(symbs,'W'); // Ɉɬɨɛɪɚɠɟɧɢɟ ɫɨɞɟɪɠɢɦɨɝɨ ɦɚɫɫɢɜɚ: show(symbs); // ɋɨɡɞɚɧɢɟ ɰɟɥɨɱɢɫɥɟɧɧɨɝɨ ɦɚɫɫɢɜɚ ɜɵɡɨɜɨɦ ɦɟɬɨɞɚ: int[] nums=create // Ɂɚɩɨɥɧɟɧɢɟ ɦɚɫɫɢɜɚ ɱɢɫɥɚɦɢ: fill(nums,3); // Ɉɬɨɛɪɚɠɟɧɢɟ ɫɨɞɟɪɠɢɦɨɝɨ ɦɚɫɫɢɜɚ: show(nums); Результат выполнения программы может (с учетом того, что используется генератор случайных чисел) быть таким: Результат выполнения программы (из листинга 7.3) |one|two|three| |2|3|5|8|13|21| Глава 7 340 ɋɥɭɱɚɣɧɵɟ ɱɢɫɥɚ: 2 21 5 5 21 5 8 8 21 8 |c|h|a|r|l|i| ɋɥɭɱɚɣɧɵɟ ɫɢɦɜɨɥɵ: a i c r i a r c a В классе с главным методом описывается несколько статических обобщенных методов. Есть метод show(), аргументом которого является массив обобщенного типа (обобщенный тип обозначен как T, а тип аргумента обозначен как T[] — то есть ссылка на массив, элементы которого относятся к типу T). Методом отображаются значения элементов массива. Обобщенный метод create() получает в качестве аргумента целое число, а результатом возвращает массив (незаполненный) из элементов обобщенного типа. В теле метода командой T[] array=new T[n] создается массив из n (целочисленный аргумент метода) элементов типа T обобщенный параметр. Ссылка на этот массив возвращается результатом метода (команда return Обобщенный метод fill() предназначен для заполнения массива значениями (все элементы массива получают одинаковые значения. Ссылка на массив и присваиваемое элементам массива значение передаются аргументами методу. Наконец, в программе есть метод getRand(), который результатом возвращает значение одного из элементов массива, переданного первым аргументом методу (первый аргумент обозначен как a). Элемент выбирается случайным образом. Для этого в качестве второго аргумента методу передается ссылка на объект класса Random (второй аргумент обозначен как rnd), с помощью которого генерируется случайное число (индекс элемента. Индекс генерируется инструкцией rnd.Next(a.Length) случайное число в диапазоне от 0 до a.Length-1 включительно. Результатом метода возвращается значение элемента с соответствующим индексом (команда return В методе Main() создается объект rnd для генерирования случайных чисел, а также три массива A (текстовый, B (целочисленный) и C символьный. Для отображения содержимого массивов используются Обобщенные типы 341 команды show(A), show(B) и show(C). Результатом выражения getRand(B,rnd) является значение одного из элементов (выбирается случайным образом) массива B. Аналогично результат выражения getRand(C,rnd) — это значение случайно выбранного элемента из массива При выполнении команды char[] symbs=create nums=create ƍWƍ) и fill(nums,3). Отображается содержимое массивов с помощью метода Примечателен и тот факт, что обобщенные методы можно перегружать в программе может быть несколько версий обобщенного метода. Как это делается на практике, показано в листинге Листинг 7.4. Перегрузка обобщенных методов System; // Ƚɥɚɜɧɵɣ ɤɥɚɫɫ: class GenMethOverloadDemo{ // ɉɟɪɜɚɹ ɜɟɪɫɢɹ ɦɟɬɨɞɚ: static void show Console.WriteLine( Ǝȼɟɪɫɢɹ ʋ1Ǝ); Console.WriteLine( ƎȺɪɝɭɦɟɧɬ: {0}Ǝ,a); } // ȼɬɨɪɚɹ ɜɟɪɫɢɹ ɦɟɬɨɞɚ: static void show(int a){ Console.WriteLine( Ǝȼɟɪɫɢɹ ʋ2Ǝ); Console.WriteLine( Ǝɑɢɫɥɨ: {0}Ǝ,a); } Глава 7 342 // Ɍɪɟɬɶɹ ɜɟɪɫɢɹ ɦɟɬɨɞɚ: static void show Console.WriteLine( Ǝȼɟɪɫɢɹ ʋ3Ǝ); Console.WriteLine( Ǝɉɟɪɜɵɣ: {0}Ǝ,a); Console.WriteLine( Ǝȼɬɨɪɨɣ: {0}Ǝ,b); } // ɑɟɬɜɟɪɬɚɹ ɜɟɪɫɢɹ ɦɟɬɨɞɚ: static void show Console.WriteLine( Ǝȼɟɪɫɢɹ ʋ4Ǝ); Console.WriteLine( Ǝɉɟɪɜɵɣ: {0}Ǝ,a); Console.WriteLine( Ǝɑɢɫɥɨ: {0}Ǝ,b); } // Ƚɥɚɜɧɵɣ ɦɟɬɨɞ: static void Main(){ // ȼɵɡɨɜ ɨɛɨɛɳɟɧɧɨɝɨ ɦɟɬɨɞɚ: show( ƍAƍ); show(123); show ƍAƍ); show show( ƍBƍ,ƎBravoƎ); show( ƍCƍ,321); show ƍCƍ,321); Ниже представлен результат выполнения программы: Результат выполнения программы (из листинга 7.4) ȼɟɪɫɢɹ ʋ1 Ⱥɪɝɭɦɟɧɬ: A ȼɟɪɫɢɹ ʋ2 ɑɢɫɥɨ: 123 ȼɟɪɫɢɹ ʋ1 Обобщенные типы 65 ȼɟɪɫɢɹ ʋ1 Ⱥɪɝɭɦɟɧɬ: 123 ȼɟɪɫɢɹ ʋ3 ɉɟɪɜɵɣ: B ȼɬɨɪɨɣ: Bravo ȼɟɪɫɢɹ ʋ4 ɉɟɪɜɵɣ: C ɑɢɫɥɨ: 321 ȼɟɪɫɢɹ ʋ3 ɉɟɪɜɵɣ: C ȼɬɨɪɨɣ: В этой программе мы описали четыре версии метода show(): • Обобщенный метод с одним аргументом обобщенного типа Обычный (не обобщенный) метод с целочисленным аргументом Обобщенный метод с одним аргументом обобщенного типа и одним аргументом целочисленного типа Обобщенный метод с двумя аргументами обобщенного типа. Все версии метода show() при вызове отображают в консольном окне значения аргумента или аргументов, нов любом случае можно определить версию метода, которая была вызвана. В главном методе метод show() вызывается с разными аргументами. При выполнении команды show( ƍAƍ) однозначно вызывается обобщенный метод с одним аргументом. А вот при выполнении команды show(123) появляется некоторая интрига относительно версии метода, которую следует вызвать (обобщенный метод с одним аргументом или обычный метод с целочисленным аргументом. Приоритет остается за обычной версией метода. Но если мы при вызове метода в угловых скобках укажем значение для обобщенного параметра (как в команде show ), то будет вызван обобщенный метод. Аналогичная ситуация имеет место ив случае передачи двух аргументов методу show() . При выполнении команды show( ƍBƍ,ƎBravoƎ) вариантов, кроме как вызывать метод с двумя аргументами обобщенного типа, нет. Глава А вот при выполнении команды show( ƍCƍ,321) вызывается версия метода, в которой второй аргумент описан как обычный целочисленный аргумент. Если же мы указываем в угловых скобках значения для обобщенных параметров (команда show ƍCƍ,321)), то вызывается версия метода с двумя аргументами обобщенного типа НАЗ А МЕТКУ Ситуация может быть достаточно запутанной. Например, мы желаем описать две версии обобщенного метода с двумя аргументами. У первой версии метода первый аргумент обобщенного типа, авто- рой — целочисленный. Во второй версии метода первый аргумент является целочисленным, а второй — обобщенного типа. В таком случае вызов метода с двумя целочисленными аргументами будет невозможен, поскольку невозможно однозначно определить, какая версия метода вызывается. Обобщенный метод может быть и нестатическим: такой метод описывается в обычном (не обобщенном) классе. В листинге 7.5 приведен пример подобной ситуации. Листинг 7.5. Нестатические обобщенные методы System; // Ʉɥɚɫɫ ɫ ɨɛɨɛɳɟɧɧɵɦ ɦɟɬɨɞɨɦ: class MyClass{ // Ɂɚɤɪɵɬɨɟ ɬɟɤɫɬɨɜɨɟ ɩɨɥɟ: public string text; // Ʉɨɧɫɬɪɭɤɬɨɪ: public MyClass(string t){ text=t; } // Ɉɛɨɛɳɟɧɧɵɣ ɦɟɬɨɞ: public void show Console.WriteLine(text+ Ǝ: Ǝ+arg); } } Обобщенные типы Ƚɥɚɜɧɵɣ ɤɥɚɫɫ: class MyClassWithGenMethodDemo{ // Ƚɥɚɜɧɵɣ ɦɟɬɨɞ: static void Main(){ // ɋɨɡɞɚɧɢɟ ɨɛɴɟɤɬɨɜ: MyClass A=new MyClass( ƎAlphaƎ); MyClass B=new MyClass( ƎBravoƎ); // ȼɵɡɨɜ ɨɛɨɛɳɟɧɧɨɝɨ ɦɟɬɨɞɚ: A.show(100); B.show(200); A.show( ƍAƍ); B.show ƍBƍ); B.show ƍBƍ); Результат выполнения программы такой: Результат выполнения программы (из листинга 7.5) Alpha: 100 Bravo: 200 Alpha: A Bravo: B Bravo: В программе описывается класс MyClass с текстовым полем. В классе есть обобщенный метод show(). Метод получает аргумент обобщенного типа и отображает в консольном окне значение этого аргумента. Вместе со значением аргумента отображается значение текстового поля объекта. В главном методе создается два объекта класса MyClass, и из этих объектов вызывается метод show(). Результаты вызовов вполне предсказуемы Глава Обобщенные классы Уэф, ты когда-нибудь видел, чтобы такой маленький пацак был таким меркантильным кю? из к/ф «Кин-дза-дза» Обобщенный класс — это класс, в котором некоторые (или все) типы представлены обобщенными параметрами. Конкретные значения для типов данных определяются на этапе создания объекта класса. Зачем такие классы нужны и какая от них польза Вообще, обобщенный класс представляет собой конструкцию еще более абстрактную, чем обычный класс. Например, мы хотим создавать объекты с двумя полями. Если мы описываем обычный класс, тов таком классе мы должны указать типы полей. Но если мы описываем обобщенный класс, то типы полей можно указать с помощью обобщенных параметров, а затем, уже при создании объекта, определяются значения типов. Получается, что обобщенный класс представляет собой некий шаблон для обычного класса. То есть он «инкапсулирует» в себе различные классы однотипной структуры — в данном случае это классы, у которых два поляне важно, какого типа. Обобщенные классы удобно использовать в тех случаях, когда объекты, с которыми предстоит иметь дело, должны иметь однотипную структуру, но при этом тип данных может быть разным. Допустим, нам необходимо хранить данные в виде массива и для этой цели предполагается использовать специальные объекты-контейнеры, содержащие соответствующий массив и имеющие методы для работы сданными из массива. Если так, то тип элементов массива отходит на второй план. Его можно реализовать через обобщенный параметра в самом обобщенном классе описать универсальные алгоритмы (реализовав их в виде методов, применимые для данных любого типа. А конкретный тип данных, которые будут храниться в контейнере, определяется на этапе создания объекта НАЗ А МЕТКУ Возвращаясь к примеру с классом с двумя полями, разницу между обычными обобщенным классом можно определить так. Обычный класс позволяет создавать объекты с двумя полями определенного типа (скажем, int и char ). С помощью обобщенного класса можно создавать объекты с двумя полями любого типа Обобщенные типы 347 Как же описывается обобщенный класс В принципе, также, как и обычный (не обобщенный. Только в угловых скобках после названия класса указывается обобщенный параметр (или параметры, обозначающий тип данных. Этот параметр (или параметры) используется в теле класса, отождествляя собой некоторый тип (какой именно, становится понятно при создании объекта на основе класса. А объект класса тоже создается как обычный объектно кроме названия обобщенного класса в угловых скобках после имени класса указывается значение (или значения) для обобщенных параметров. Шаблон описания обобщенного класса следующий ɢɦɹ_ɤɥɚɫɫɚ<ɩɚɪɚɦɟɬɪ(ɵ)_ɬɢɩɚ>{ // Ʉɨɞ При создании объекта на основе обобщенного класса используем следующий шаблон ɨɛɴɟɤɬ=new Фактически, если под названием класса подразумевать имя класса с угловыми скобками и указанными в них значениями типов данных, процесс создания объекта представляется традиционным. Теперь рассмотрим программу в листинге 7.6, в которой есть примеры описания и использования обобщенных классов. Листинг 7.6. Знакомство с обобщенными классами System; // Ɉɛɨɛɳɟɧɧɵɣ ɤɥɚɫɫ c ɨɞɧɢɦ ɩɚɪɚɦɟɬɪɨɦ: class Alpha // ɉɨɥɟ ɨɛɨɛɳɟɧɧɨɝɨ ɬɢɩɚ: public X code; // Ʉɨɧɫɬɪɭɤɬɨɪ: public Alpha(X a){ code=a; } // Ɇɟɬɨɞ: public void show(){ Глава 7 348 Console.WriteLine( Ǝɉɨɥɟ ɬɢɩɚ {0}: {1}Ǝ,typeof(X).Name,code); } } // Ɉɛɨɛɳɟɧɧɵɣ ɤɥɚɫɫ ɫ ɞɜɭɦɹ ɩɚɪɚɦɟɬɪɚɦɢ: class Bravo // ɉɨɥɹ ɨɛɨɛɳɟɧɧɨɝɨ ɬɢɩɚ: public X first; public Y second; // Ʉɨɧɫɬɪɭɤɬɨɪ: public Bravo(X a,Y b){ first=a; second=b; } // Ɇɟɬɨɞ: public void show(){ Console.WriteLine( Ǝɉɟɪɜɨɟ ɩɨɥɟ ɬɢɩɚ {0}: {1}Ǝ,typeof(X).Name,first); Console.WriteLine( Ǝȼɬɨɪɨɟ ɩɨɥɟ ɬɢɩɚ {0}: {1}Ǝ,typeof(Y).Name,second); } } // Ƚɥɚɜɧɵɣ ɤɥɚɫɫ: class GenClassDemo{ // Ƚɥɚɜɧɵɣ ɦɟɬɨɞ: static void Main(){ // ɋɨɡɞɚɧɢɟ ɨɛɴɟɤɬɨɜ ɨɛɨɛɳɟɧɧɨɝɨ ɤɥɚɫɫɚ: Alpha Alpha Ǝobject BƎ); Alpha ƍCƍ); // ȼɵɡɨɜ ɦɟɬɨɞɨɜ ɢɡ ɨɛɴɟɤɬɨɜ ɨɛɨɛɳɟɧɧɨɝɨ ɤɥɚɫɫɚ: A.show(); B.show(); C.show(); Console.WriteLine(); Обобщенные типы // ɋɨɡɞɚɧɢɟ ɨɛɴɟɤɬɨɜ ɨɛɨɛɳɟɧɧɨɝɨ ɤɥɚɫɫɚ: Bravo ƍAƍ); Bravo ƎobjBƎ,true); Bravo ƍBƍ,ƍCƍ); // ȼɵɡɨɜ ɦɟɬɨɞɨɜ ɢɡ ɨɛɴɟɤɬɨɜ ɨɛɨɛɳɟɧɧɨɝɨ ɤɥɚɫɫɚ: objA.show(); objB.show(); objC.show(); Результат выполнения программы такой: Результат выполнения программы (из листинга 7.6) ɉɨɥɟ ɬɢɩɚ Int32: 123 ɉɨɥɟ ɬɢɩɚ String: object B ɉɨɥɟ ɬɢɩɚ Char: C ɉɟɪɜɨɟ ɩɨɥɟ ɬɢɩɚ Int32: 123 ȼɬɨɪɨɟ ɩɨɥɟ ɬɢɩɚ Char: A ɉɟɪɜɨɟ ɩɨɥɟ ɬɢɩɚ String: objB ȼɬɨɪɨɟ ɩɨɥɟ ɬɢɩɚ Boolean: True ɉɟɪɜɨɟ ɩɨɥɟ ɬɢɩɚ Char: B ȼɬɨɪɨɟ ɩɨɥɟ ɬɢɩɚ Char: Программа простая. В ней мы описываем два обобщенных класса класс Alpha описан с одним обобщенным параметром (обозначен как X), а класс Bravo описан с двумя обобщенными параметрами (обозначены как X и Y). В описании классов обобщенные параметры указываются в угловых скобках после имени класса. В классе Alpha есть поле code обобщенного типа X, а также метод show() , при вызове которого в консольном окне отображается информация о значении обобщенного параметра X и значении поля code. Также в классе Alpha есть конструктор с одним аргументом (типа X). Глава Переданный конструктору аргумент присваивается в качестве значения полю Класс Bravo подобен классу Alpha, нос поправкой на то, что в классе Bravo два обобщенных параметра (X и Y), два поля (поле first типа X и поле second типа Y), у конструктора два аргумента, а метод show() при вызове отображает значение параметров X и Y, а также значение полей и second. { i НАЗ А МЕТКУ Методы в обобщенном классе описываются как обычные то есть после имени метода обобщенные параметры в угловых скобках указывать ненужно. В случае необходимости они просто используются в методе. Это же относится к вызову методов. Если объект создается на основе обобщенного класса, то значения для обобщенных параметров определяются на этапе создания объекта. При вызове метода из объекта нет необходимости как-то определять эти параметры. В главном методе создаются объекты классов Alpha и Bravo, и из этих объектов вызывается метод show(). Хочется верить, что результат выполнения соответствующих команд особых комментариев не требует НАЗ А МЕТКУ При создании объекта на основе обобщенного класса значения обобщенных параметров указываются в угловых скобках после имени класса и при объявлении объектной переменной, ив инструкции создания объекта класса. |