Generalizations (templates). Parameterized types. Generic classes, interfaces, methods
Contents
- 1. What is “generalization” (template) in Java? What is a parameterized type? Specifics of using generics
- 2. The advantages of using generalizations
- 3. The general form of declaring a generic class and declaring a reference to a generic class
- 4. What types are prohibited from being used in generic classes as parameterized types?
- 5. An example of a generic class that implements a method for finding an element in a two-dimensional matrix
- 6. An example implementation of a method that performs a cyclic shift in an array of the generic type Type
- 7. An example of a class that receives two parameterized types
- Related topics
Search other websites:
1. What is “generalization” (template) in Java? What is a parameterized type? Specifics of using generics
Generalization is a mechanism for building a program code for a certain type with an arbitrary name in order to further convert it to another specific reference type. Conversion from a generic type to another (specific) type is implemented by the compiler.
Generics can be applied to classes, interfaces, or methods. If a class, interface or method operates on some generic type T, then this class (interface, method) is called generic. A type that receives a generic class as a parameter is called a parameterized type.
Generics can be applied to classes, interfaces, or methods. If a class, interface or method operates on some generic type T, then this class (interface, method) is called generic. A type that receives a generic class as a parameter is called a parameterized type. The name of a parameterized type can be anything (T, Type, TT, etc.).
⇑
2. The advantages of using generalizations
Using generics in Java provides the following benefits:
- compactness of the program code is provided;
- thanks to generalizations, all casts are done automatically and implicitly. Reusable code is easier and safer to handle;
- generalizations provide type safety as opposed to using references to Object type. This means that using a reference to the Object class, you can operate with different types of objects. However, this method does not provide type safety.
⇑
3. The general form of declaring a generic class and declaring a reference to a generic class
For a method of a class to operate on the generic type Type, the class (interface) must be declared as generic. The Java language allows a class to be declared for one or more generic types. The general form of a class that uses generic types is as follows:
class ClassName<Type1, Type2, ..., TypeN> { // ... }
here
- ClassName – the nsme of class;
- Type1, Type2, TypeN – the types that the ClassName class operates on.
Most often, a generic class operates with one type. In this case, the general form of the class is:
class ClassName<Type> { // ... }
The general form of declaring a reference to a generic class is as follows
ClassName<Type1, Type2, ..., TypeN> VarName =
new ClassName<Type1, Type2, ..., Type>(argument_list);
where
- ClassName – the name of class;
- VarName – the name of the reference to the instance of the class that is created by the new operator;
- argument_list – a list of arguments that the class constructor receives.
For example, if you declare a class in the program that receives the type T as a parameter
class SomeClass<T> {
}
then in this class you can implement variables and methods that are of type T
class SomeClass<T> { // Declaring variables with type T T var1, var2, ..., varN; // Method declaration using type T public return_type SomeMethod(T param1, T param2, ..., T paramN) { // Implementation of the SomeMethod() method using type T // ... } }
After the declaration, the use of the above class for Integer type will be as follows
SomeClass<Integer> objInt = new SomeClass<Integer>();
objInt.SomeMethod(arg1, arg2, ..., argN);
In the above declaration, the type Integer is a type argument.
Instantiating a class for type Double is as follows
SomeClass<Double> objDouble = new SomeClass<Double>();
Likewise, the generic class SomeClass<T> can be used for any other type.
⇑
4. What types are prohibited from being used in generic classes as parameterized types?
When using generic classes, the type parameter must only be of a reference type. When using a generic class, it is forbidden to use base types (int, char, double, etc.) as a type argument.
That is, if the following class is specified
class SomeClass<T> { // ... }
then you will not be able to declare an instance of type int or other base type
SomeClass<int> objInt = new SomeClass<int>(); // Error
Instead of int, you must use the Integer wrapper class.
Similarly, for other base types, you need to use the wrapper classes: double -> Double, float-> Float, boolean-> Boolean, etc.
⇑
5. An example of a generic class that implements a method for finding an element in a two-dimensional matrix
The generic class GenericMatrix<Type> is declared, which implements the SearchKey() method, which calculates the number of occurrences of the given key element in the matrix.
The SearchKey() method receives the following parameters:
- M – the initial matrix of the generic type Type[][], in which the key is searched;
- m, n – the dimension of the matrix, the number of rows and columns, respectively;
- key – a key (element), the number of occurrences of which in the matrix M needs to be calculated.
// Generic class operating on Type type class GenericMatrix<Type> { // A method that counts the number of key elements in a two-dimensional matrix M. public int SearchKey(Type[][] M, int m, int n, Type key) { int count = 0; for (int i=0; i<m; i++) for (int j=0; j<n; j++) if (key==M[i][j]) count++; return count; } } public class TestGeneric<Type> { public static void main(String[] args) { // Demonstration of using the SearchKey method in the GenericMatrix<Type> class // Declaring internal variables int count; // Source matrix Integer[][] MI = { { 2, 5, -8 }, { 3, 1, 5 }, { 4, 8, 2 }, { 5, 1, 8 } }; // Create an instance of the GenericMatrix<Type> class GenericMatrix<Integer> obj = new GenericMatrix<Integer>(); // Call the SearchKey() method of the instance count = obj.SearchKey(MI, 4, 3, 8); // Print the result System.out.println("count = " + count); // count = 2 } }
⇑
6. An example implementation of a method that performs a cyclic shift in an array of the generic type Type
The example implements the GenericClass<Type> class, which contains the following methods:
- CyclicShift() – implements a cyclic shift in a one-dimensional array, the elements of which are of the generalized type Type;
- Print() – implements the output of an array of the generic type Type to the screen;
- main() – demonstrates the use of the class.
// A class that has a cyclic shift method in an array of the generic Type public class GenericClass<Type> { // Cyclic shift in array A by count positions. // Parameters: // - A - source array; // - count - the number of positions to shift; // - direction - direction (true - left, false - right). public void CyclicShift(Type[] A, int count, boolean direction) { Type item; int iterations = (int)(count % A.length); // remove unnecessary iterations if (direction) { // Shift left for (int i=0; i<iterations; i++) { item = A[0]; for (int j=0; j<A.length-1; j++) A[j] = A[j+1]; A[A.length-1] = item; } } else { // Shift right for (int i=0; i<iterations; i++) { item = A[A.length-1]; for (int j=A.length-2; j>=0; j--) A[j+1] = A[j]; A[0] = item; } } } // A method that outputs an array of the generic Type with the comment text public void Print(Type[] A, String text) { System.out.println(text); for (int i=0; i<A.length; i++) { System.out.print(A[i] + " | "); } System.out.println(); } public static void main(String[] args) { //Demonstration of using the CyclicShift() method in the TestGeneric<Type> class // for type String // Source array String[] AS = { "1-abc", "2-cde", "3-fgh", "4-jklmn", "5-jprst" }; // Declare an instance of TestGeneric<Type> class TestGeneric<String> obj = new TestGeneric<String>(); // Print ghe array AS obj.Print(AS, "Array AS. Before: "); // Implement circular shift for type String obj.CyclicShift(AS, 3, true); // shift 3 positions to the left // Print the AS array again obj.Print(AS, "Array AS. After:"); // ------------------------------------- // Using CyclicShift() method for Double reference type Double[] AD = { 1.5, 1.3, 1.1, 0.8, 0.5, 0.2 }; TestGeneric<Double> objD = new TestGeneric<Double>(); objD.Print(AD, "Array AD. Before: "); objD.CyclicShift(AD, 2, false); // Move 2 positions to the right objD.Print(AD, "Array AD. After:"); // Using Cyclic Shift() method for Integer reference type Integer[] AI = { 5, 3, 2, -1, -8, 4, 3, 0, 12 }; TestGeneric<Integer> objI = new TestGeneric<Integer>(); objI.Print(AI, "Array AI. Before:"); objI.CyclicShift(AI, 6, true); // shift 6 positions to the left objI.Print(AI, "Array AI. After: "); } }
The program result
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. An example of a class that receives two parameterized types
A class can receive several types as parameters. Below is an example of a class that takes two types T1, T2 as parameters. The class implements the Print() method, which outputs the value of arrays of elements of types T1 and T2.
// A class that takes as parameters two types T1, T2 public class GenericClass<T1, T2> { // Method that prints single elements of types T1, T2 public void Print(T1 item1, T2 item2, String comment) { System.out.println(comment); System.out.println("item1 = " + item1); System.out.println("item2 = " + item2); System.out.println("The type of item1 = " + item1.getClass()); System.out.println("The type of item2 = " + item2.getClass()); } // Method that prints arrays of elements of generic types T1, T2 public void Print(T1[] A1, T2[] A2, String comment) { System.out.println(comment); System.out.print("A1 = { "); for (int i=0; i<A1.length; i++) System.out.print(A1[i] + " "); System.out.println(" }"); System.out.print("A2 = { "); for (int i=0; i<A2.length; i++) System.out.print(A2[i] + " "); System.out.println(" }"); System.out.println("The type of array A1 = " + A1.getClass()); System.out.println("Tye type of array A2 = " + A2.getClass()); } public static void main(String[] args) { // Demonstration of using the GenericClass<T1, T2> class that takes two type parameters // 1. Using the Print() method for single elements of different types // 1.1. Declare variables of different types Integer item1 = 23; Double item2 = 2.85; // 1.2. Declare the obj1 instance GenericClass<Integer, Double> obj1 = new GenericClass<Integer, Double>(); // 1.3. Invoke Print() method on single items obj1.Print(item1, item2, "The values of item1 and item2:"); // 2. Using method Print() for arrays // 2.1. Declare arrays Float[] AF = { 3.8f, 2.5f, -1.4f, 2.2f, 0.001f }; Boolean[] AB = { true, true, false, true, false }; // 2.2. Declare instance obj2 GenericClass<Float, Boolean> obj2 = new GenericClass<Float, Boolean>(); // 2.3. Invoke Print() for arrays obj2.Print(AF, AB, "The values of arrays AF, AB"); } }
The result of the program
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; Tye type of array A2 = class [Ljava.lang.Boolean;
⇑
Related topics
- Ensuring type safety by using generalizations. Generalized interfaces. Examples
- Limited types. Metacharacter arguments. Examples
⇑