В Java Generics — это параметризованные типы, которые позволяют нам создавать классы, интерфейсы и методы, в которых тип данных, с которыми они имеют дело, будет указан в качестве параметра. Это обеспечивает безопасность типов во время компиляции.
Синтаксис
class class_name<T> { //Body of the class }
Здесь T — это параметр типа, который можно заменить любым допустимым идентификатором. Точно так же создаются универсальные методы и интерфейсы.
Ограничения дженериков в Java
Есть несколько ограничений, связанных с использованием дженериков, которые упомянуты ниже:
- Параметры типа не могут быть созданы
- Ограничение на использование статических членов
- Общий массив Ограничения
- Примитивные типы данных не используются с универсальными типами
- Общее ограничение исключения
1. Параметры типа не могут быть созданы
Невозможно создать экземпляр параметра типа. Компилятор не знает, какой тип объекта создать, их T — просто заполнитель. Ниже приведен пример кода, который показывает недопустимое создание экземпляра T, что приводит к ошибке компиляции.
Пример:
Java
// Java Program to demonstrate Generic class creation with
// the type parameter T.
class
GenType<T> {
private
T data;
GenType(T data)
{
// parameterized constructor
this
.data = data;
}
T getData() {
return
data; }
// main function
public
static
void
main(String[] args)
{
GenType<Integer> gt =
new
GenType<>(
10
);
System.out.println(gt.getData());
}
}
Выход
10
2. Ограничение на использование статических членов
Статические члены (переменные, методы) не могут использовать параметр типа, объявленный окружающим классом. В этом случае мы будем использовать приведенный выше пример, чтобы сделать переменную и метод статическими, это также приводит к ошибке времени компиляции. Давайте посмотрим подробно, что говорит компилятор:
Пример:
Java
// Java Program to demonstrate Generic class creation with
// type parameter T.
class
GenType<T> {
// illegal to make a variable as static.
// static T data; //compile-time Error:Cannot make a
// static reference to the non-static type T
T data;
GenType() {}
GenType(T data)
{
// parameterized constructor
this
.data = data;
}
T getData() {
return
data; }
public
static
void
main(String[] args)
{
GenType<String> gt
=
new
GenType<>(
"Geek For Geeks!!"
);
System.out.println(gt.getData());
}
}
Выход
Geek For Geeks!!
3. Общие ограничения массива
К массивам применяются два важных общих ограничения.
- Мы не можем создать экземпляр массива, тип элемента которого является параметром типа. У компилятора нет возможности узнать, какой тип массива на самом деле создать. Однако мы можем передать ссылку на совместимый по типу массив в качестве параметра и присвоить его созданному объекту. Это допустимо, поскольку массив, передаваемый в качестве параметра, имеет известный тип, который будет того же типа, что и T на момент создания объекта.
- Мы не можем создать массив универсальных ссылок для конкретного типа. Причина может быть той же, что и в приведенном выше случае, когда компилятор не знает, какой массив создавать. Это можно решить с помощью подстановочного знака, что лучше, чем использование необработанного типа, поскольку будет выполнена по крайней мере некоторая проверка типа.
Пример:
Java
// Java Program to implement
// Generic array Restrictions
import
java.util.Arrays;
public
class
GenArray<T
extends
Number> {
T obj;
T arr[];
GenArray(T o, T[] vals)
{
this
.obj = o;
System.out.println(
"value: "
+ obj);
// Invalid
// arr = new T[10];
// compile-time Error:Cannot
// create a generic array of T
// But, this is allowed because we are assigning the
// reference to the existing array.
arr = vals;
}
T[] getArray() {
return
arr; }
public
static
void
main(String[] args)
{
Integer[] Array = {
1
,
2
,
3
,
4
,
5
};
GenArray<Integer> obj1
=
new
GenArray<Integer>(
10
, Array);
System.out.println(
Arrays.toString(obj1.getArray()));
// illegal to create an array of type-specific
// generic references.
}
}
Выход
value: 10 [1, 2, 3, 4, 5]
4. Примитивные типы данных не используются с универсальными типами.
Мы получим ошибку компиляции, если будем использовать примитивные типы данных во время создания объекта. Следующий код демонстрирует ситуацию:
Пример:
Java
// Java Program to implement
// Primitive data types are not
// used with the generic types
import
java.io.*;
// Driver Class
class
Box<T> {
private
T data;
Box(T data) {
this
.data = data; }
T getData() {
return
data; }
public
static
void
main(String[] args)
{
Box<Integer> b1 =
new
Box<Integer>(
10
);
// use of wrapper classes
Box<String> b2 =
new
Box<String>(
"Geek For Geeks"
);
System.out.println(
"value: "
+ b1.getData());
System.out.println(
"value: "
+ b2.getData());
}
}
Выход
value: 10 value: Geek For Geeks
5. Общее ограничение исключения
Мы не можем создавать общие классы исключений и не можем расширять throwable (который превосходит все классы исключений в иерархии классов исключений). Мы будем использовать приведенный выше пример, чтобы понять это, хотя мы получим ошибку, если выполним этот код, попробуйте.
Пример:
Java
// Java Program to implement
// Generic Exception Restriction
import
java.io.*;
// generic class cannot extend throwable
class
Box<T>
extends
Throwable {
private
T data;
Box(T data) {
this
.data = data; }
T getData() {
return
data; }
// main function
public
static
void
main(String[] args)
{
Box<Integer> b1 =
new
Box<Integer>(
10
);
System.out.println(
"value: "
+ b1.getData());
}
}
Выход:
Error: Could not find or load main class Box Caused by: java.lang.ClassNotFoundException: Box