Обобщенные классы (Generic classes) - это классы, обладающие параметрическим полиморфизмом (т. е. классы, которые изменяют свое поведение в зависимости от приписываемого им типа. Этот тип указывается в квадратных скобках []
сразу после имени класса). Они особенно полезны для создания коллекций.
Объявление обобщенного класса
Для объявления обобщенного класса необходимо после имени добавить тип в квадратных скобках []
как еще один параметр класса. По соглашению обычно используют заглавные буквы A
, хотя можно использовать любые имена.
class Stack[A] {
private var elements: List[A] = Nil
def push(x: A): Unit =
elements = x :: elements
def peek: A = elements.head
def pop(): A = {
val currentTop = peek
elements = elements.tail
currentTop
}
}
class Stack[A]:
private var elements: List[A] = Nil
def push(x: A): Unit =
elements = x :: elements
def peek: A = elements.head
def pop(): A =
val currentTop = peek
elements = elements.tail
currentTop
Данная реализация класса Stack
принимает в качестве параметра любой тип A
. Это означает что список, var elements: List[A] = Nil
, может хранить только элементы типа A
. Процедура def push
принимает только объекты типа A
(примечание: elements = x :: elements
переназначает elements
в новый список, созданный путем добавления x
к текущим elements
).
Здесь Nil
— это пустой List
, и его не следует путать с null
.
Использование
Чтобы использовать обобщенный класс, поместите конкретный тип в квадратные скобки вместо A
.
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop()) // выведет 2
println(stack.pop()) // выведет 1
val stack = Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop()) // выведет 2
println(stack.pop()) // выведет 1
Экземпляр stack
может принимать элементы типа Int
. Однако, если тип имеет подтипы, то они также могут быть приняты:
class Fruit
class Apple extends Fruit
class Banana extends Fruit
val stack = new Stack[Fruit]
val apple = new Apple
val banana = new Banana
stack.push(apple)
stack.push(banana)
class Fruit
class Apple extends Fruit
class Banana extends Fruit
val stack = Stack[Fruit]
val apple = Apple()
val banana = Banana()
stack.push(apple)
stack.push(banana)
Классы Apple
и Banana
наследуются от Fruit
так, что мы можем засунуть экземпляры Apple
и Banana
в пачку Fruit
.
Примечание: подтипы обобщенных типов - *инвариантны*. Это означает, что если у нас есть стэк символов типа Stack[Char]
, то он не может быть использован как стек интов типа Stack[Int]
. Это нежелательное поведение, потому как позволило бы нам добавлять в стек символов целые числа. В заключение, Stack[A]
является подтипом Stack[B]
тогда и только тогда, когда B = A
. Поскольку это может быть довольно строгим ограничением, Scala предлагает механизм вариативного описания параметров типа для контроля за поведением подтипов.
Contributors to this page:
Contents
- Введение
- Основы
- Единобразие типов
- Классы
- Значения Параметров По умолчанию
- Именованные Аргументы
- Трейты
- Кортежи
- Композиция классов с трейтами
- Функции Высшего Порядка
- Вложенные Методы
- Множественные списки параметров (Каррирование)
- Классы Образцы
- Сопоставление с примером
- Объекты Одиночки
- Регулярные Выражения
- Объект Экстрактор
- Сложные for-выражения
- Обобщенные Классы
- Вариантность
- Верхнее Ограничение Типа
- Нижнее Ограничение Типа
- Внутренние классы
- Члены Абстрактного Типа
- Составные Типы
- Самоописываемые типы
- Контекстные параметры, также известные, как неявные параметры
- Неявные Преобразования
- Полиморфные методы
- Выведение Типа
- Операторы
- Вызов по имени
- Аннотации
- Пакеты и Импорт
- Объекты Пакета