Параметризированные типы в java

Java. Обобщения (шаблоны). Параметризованные типы. Обобщенные классы

Обобщение – это механизм построения программного кода для некоторого типа с произвольным именем с целью его дальнейшего конвертирования (преобразования) в другой конкретный ссылочный тип. Реализацию конвертирования из обобщенного типа в другой (конкретный) осуществляет компилятор.

Обобщения могут быть применены к классам, интерфейсам или методам. Если класс, интерфейс или метод оперирует некоторым обобщенным типом T , то этот класс (интерфейс, метод) называется обобщенным. Тип, который получает обобщенный класс в качестве параметра, называется параметризованным типом. Имя параметризованного типа можно задавать любым ( T , Type , TT и т.д.).

2. Преимущества применения обобщений

Использование обобщений в языке Java дает следующие преимущества:

  • обеспечивается компактность программного кода;
  • благодаря обобщениям все операции приведения типов выполняются автоматически и неявно. Повторно используемый код обрабатывается более легко и безопасно;
  • обобщения обеспечивают типовую безопасность типов в отличие от использования ссылок на тип Object . Как известно, в языке Java все классы или интерфейсы являются подклассами класса Object . Это значит, что с помощью ссылки на класс Object можно оперировать разнотипными объектами. Однако, такой способ не обеспечивает типовой безопасности типов.
3. Общая форма объявления обобщенного класса и объявление ссылки на обобщенный класс

Чтобы метод некоторого класса оперировал обобщенным типом Type , нужно чтобы класс (интерфейс) был объявлен как обобщенный. В языке Java допускается объявление класса для одного или нескольких обобщенных типов. Общая форма класса, который использует обобщенные типы, следующая:

class ClassNameType1, Type2, . TypeN> < // . >
  • ClassName – имя класса;
  • Type1 , Type2 , TypeN – типы, с которыми оперирует класс ClassName .

Чаще всего обобщенный класс оперирует с одним типом. В этом случае общая форма класса имеет вид:

class ClassNameType> < // . >

Общая форма объявления ссылки на обобщенный класс следующая

ClassName VarName =  new ClassName(argument_list);
  • ClassName – имя класса;
  • VarName – имя ссылки на экземпляр класса, который создается оператором new ;
  • argument_list – список аргументов, которые получает конструктор класса.
Читайте также:  Link States

Например, если в программе объявить класс, который получает параметром тип T

class SomeClass

то в этом классе можно реализовывать переменные и методы, которые имеют тип T

class SomeClass < // Объявление переменных с типом T T var1, var2, . varN; // Объявление метода, использующего тип T public return_type SomeMethod(T param1, T param2, . T paramN) < // Реализация метода SomeMethod(), использущего тип T // . > >

После объявления, использование вышеприведенного класса для типа Integer будет следующим

SomeClass objInt = new SomeClass(); objInt.SomeMethod(arg1, arg2, . argN);

В вышеприведенном объявлении тип Integer есть аргументом типа.

Создание экземпляра класса для типа Double следующее

SomeClass objDouble = new SomeClass();

Подобным образом обобщенный класс SomeClass может использоваться для любых других типов.

4. Какие типы запрещается использовать в обобщенных классах в качестве параметризованных типов?

При использовании обобщенных классов параметр типа должен быть только ссылочного типа. При использовании обобщенного класса запрещается использовать базовые типы ( int , char , double и т.д.) в качестве аргумента типа.

class SomeClass < // . >

то объявить экземпляр типа int или другого базового типа не удастся

SomeClassint> objInt = new SomeClass(); // Ошибка

Вместо типа int нужно использовать класс-обертку Integer .

Аналогично для других базовых типов нужно использовать классы-обертки: double -> Double , float->Float , boolean->Boolean и т.д.

5. Пример обобщенного класса, который реализует метод поиска элемента в двумерной матрице

Объявляется обобщенный класс GenericMatrix , в котором реализован метод SearchKey() , который вычисляет количество вхождений заданного элемента key в матрице.

Метод SearchKey() получает следующие параметры:

  • M – исходная матрица обобщенного типа Type[][] , в которой осуществляется поиск ключа key ;
  • m , n – размерность матрицы, количество строк и столбцов соответственно;
  • key – ключ (элемент), количество вхождений которого в матрицу M нужно вычислить.
// Обобщенный класс, оперирующий типом Type class GenericMatrix  < // Метод, который осуществляет подсчет количества элементов key в двумерной матрице M.  public int SearchKey(Type[][] M, int m, int n, Type key) < int count = 0; for (int i=0; i for (int j=0; j if (key==M[i][j]) count++; return count; > > public class TestGeneric <  public static void main(String[] args) < // Демонстрация использования метода SearchKey в классе GenericMatrix // Объявление внутренних переменных int count; // Исходная матрица Integer[][] MI = < < 2, 5, -8 >, < 3, 1, 5 >, < 4, 8, 2 >, < 5, 1, 8 >>; // Создать экземпляр класса GenericMatrix GenericMatrix obj = new GenericMatrix(); // Вызвать метод SearchKey() экземпляра count = obj.SearchKey(MI, 4, 3, 8); // Вывести результат System.out.println("count color: #008000;">// count = 2 > >
6. Пример реализации метода, который осуществляет циклический сдвиг в массиве обобщенного типа Type

В примере реализован класс GenericClass , который содержит следующие методы:

  • CyclicShift() – реализует циклический сдвиг в одномерном массиве, элементы которого имеют обобщенный тип Type ;
  • Print() – реализует вывод массива обобщенного типа Type на экран;
  • main() – демонстрирует использование класса.
// Класс, в котором есть метод циклического сдвига в массиве обобщенного типа Type public class GenericClass  < // Циклический сдвиг в массиве A на count позиций. // Параметры: // - A - исходный массив; // - count - количество позиций, на которые осуществляется сдвиг; // - direction - направление (true - влево, false - вправо).  public void CyclicShift(Type[] A, int count, boolean direction) < Type item; int iterations = (int)(count % A.length); // убрать лишние итерации if (direction) < // Сдвиг влево for (int i=0; i for (int j=0; jlength-1; j++) A[j] = A[j+1]; A[A.length-1] = item; > > else < // Сдвиг вправо for (int i=0; ilength-1]; for (int j=A.length-2; j>=0; j--) A[j+1] = A[j]; A[0] = item; > > > // Метод, который выводит массив обобщенного типа Type с комментарием text.  public void Print(Type[] A, String text) < System.out.println(text); for (int i=0; ilength; i++) < System.out.print(A[i] + " | "); > System.out.println(); >  public static void main(String[] args) < // Демонстрация использования метода CyclicShift() в классе TestGeneric // для типа String // Исходный массив String[] AS = < "1-abc", "2-cde", "3-fgh", "4-jklmn", "5-jprst" >; // Объявить экземпляр класса TestGeneric TestGeneric obj = new TestGeneric(); // Вывести массив AS obj.Print(AS, "Array AS. Before: "); // Реализовать циклический сдвиг для типа String obj.CyclicShift(AS, 3, true); // сдвинуть на 3 позиции влево // Вывести снова массив AS obj.Print(AS, "Array AS. After:"); // ------------------------------------- // Использование метода CyclicShift() для ссылочного типа Double Double[] AD = < 1.5, 1.3, 1.1, 0.8, 0.5, 0.2 >; TestGeneric objD = new TestGeneric(); objD.Print(AD, "Array AD. Before: "); objD.CyclicShift(AD, 2, false); // Сдвинуть на 2 позиции вправо objD.Print(AD, "Array AD. After:"); // Использование метода CyclicShift() для ссылочного типа Interger Integer[] AI = < 5, 3, 2, -1, -8, 4, 3, 0, 12 >; TestGeneric objI = new TestGeneric(); objI.Print(AI, "Array AI. Before:"); objI.CyclicShift(AI, 6, true); // сдвинуть на 6 позиций влево objI.Print(AI, "Array AI. After: "); > >

Результат работы программы

Array AS. Before: 1-abc | 2-cde | 3-fgh | 4-jklmn | 5-jprst | Array AS. After: 4-jklmn | 5-jprst | 1-abc | 2-cde | 3-fgh | Array AD. Before: 1.5 | 1.3 | 1.1 | 0.8 | 0.5 | 0.2 | Array AD. After: 0.5 | 0.2 | 1.5 | 1.3 | 1.1 | 0.8 | Array AI. Before: 5 | 3 | 2 | -1 | -8 | 4 | 3 | 0 | 12 | Array AI. After: 3 | 0 | 12 | 5 | 3 | 2 | -1 | -8 | 4 |
7. Пример класса, который получает два параметризованных типа

Класс может получать несколько типов в качестве параметров. Ниже дается пример класса, который получает два типа T1 , T2 в качестве параметров. В классе реализован метод Print() , который выводит значение массивов элементов типов T1 и T2 .

// Класс, который получает в качестве параметров два типа T1, T2 public class GenericClass  < // Метод, который выводит одиночные элементы типов T1, T2  public void Print(T1 item1, T2 item2, String comment) < System.out.println(comment); System.out.println("item1 color: #0000ff;">out.println("item2 color: #0000ff;">out.println("The type of item1 color: #0000ff;">out.println("The type of item2 color: #008000;"> // Метод, который выводит массивы элементов обобщенных типов T1, T2  public void Print(T1[] A1, T2[] A2, String comment) < System.out.println(comment); System.out.print("A1 = < "); for (int i=0; ilength; i++) System.out.print(A1[i] + " "); System.out.println(" >"); System.out.print("A2 = < "); for (int i=0; ilength; i++) System.out.print(A2[i] + " "); System.out.println(" >"); System.out.println("The type of array A1 color: #0000ff;">out.println("The type of array A2 color: #800080;"> public static void main(String[] args) < // Демонстрация использования класса GenericClass, который получает два параметра типов // 1. Использование метода Print() для одиночных элементов разных типов // 1.1. Объявить переменные разных типов Integer item1 = 23; Double item2 = 2.85; // 1.2. Объявить экземпляр obj1 GenericClass obj1 = new GenericClass(); // 1.3. Вызвать метод Print() для одиночных элементов obj1.Print(item1, item2, "The values of item1 and item2:"); // 2. Использование метода Print() для массивов // 2.1. Объявить массивы Float[] AF = < 3.8f, 2.5f, -1.4f, 2.2f, 0.001f >; Boolean[] AB = < true, true, false, true, false >; // 2.2. Объявить экземпляр obj2 GenericClass obj2 = new GenericClass(); // 2.3. Вызвать метод Print() для массивов obj2.Print(AF, AB, "The values of arrays AF, AB"); > >

Результат выполнения программы

The values of item1 and item2: item1 = 23 item2 = 2.85 The type of item1 = class java.lang.Integer The type of item2 = class java.lang.Double The values of arrays AF, AB A1 = < 3.8 2.5 -1.4 2.2 0.001 >A2 = < true true false true false >The type of array A1 = class [Ljava.lang.Float; The type of array A2 = class [Ljava.lang.Boolean;

Связанные темы

Источник

Оцените статью