Что такое статический класс
Статические классы и члены статических классов (Руководство по программированию в C#)
Создание нестатического класса, который допускает создание только одного экземпляра самого себя, см. в документе Реализация Singleton в C#.
Ниже приведены основные возможности статического класса.
Содержит только статические члены.
Создавать его экземпляры нельзя.
По сути, создание статического класса аналогично созданию класса, содержащего только статические члены и закрытый конструктор. Закрытый конструктор не допускает создания экземпляров класса. Преимущество применения статических классов заключается в том, что компилятор может проверить отсутствие случайно добавленных членов экземпляров. Таким образом, компилятор гарантирует невозможность создания экземпляров таких классов.
Статические классы запечатаны, поэтому их нельзя наследовать. Они не могут наследовать ни от каких классов, кроме Object. Статические классы не могут содержать конструктор экземпляров. Однако они могут содержать статический конструктор. Нестатические классы также должен определять статический конструктор, если класс содержит статические члены, для которых нужна нетривиальная инициализация. Дополнительные сведения см. в разделе Статические конструкторы.
Пример
Ниже приведен пример статического класса, содержащего два метода, преобразующих температуру по Цельсию в температуру по Фаренгейту и наоборот.
Статический члены
Нестатический класс может содержать статические методы, поля, свойства или события. Статический член вызывается для класса даже в том случае, если не создан экземпляр класса. Доступ к статическому члены всегда выполняется по имени класса, а не экземпляра. Существует только одна копия статического члена, независимо от того, сколько создано экземпляров класса. Статические методы и свойства не могут обращаться к нестатическим полям и событиям в их содержащем типе, и они не могут обращаться к переменной экземпляра объекта, если он не передается явно в параметре метода.
Более привычно объявление нестатического класса с несколькими статическими членами, чем объявление всего класса как статического. Статические поля обычно используются для следующих двух целей: хранение счетчика числа созданных объектов или хранение значения, которое должно совместно использоваться всеми экземплярами.
Статические методы могут быть перегружены, но не переопределены, поскольку они относятся к классу, а не к экземпляру класса.
C# не поддерживает статические локальные переменные (то есть переменные, объявленные в области действия метода).
Для объявления статических методов класса используется ключевое слово static перед возвращаемым типом члена, как показано в следующем примере:
Статические члены инициализируются перед первым доступом к статическому члену и перед вызовом статического конструктора, если таковой имеется. Для доступа к члену статического класса следует использовать имя класса, а не имя переменной, указывая расположение члена, как показано в следующем примере:
Если класс содержит статические поля, должен быть указан статический конструктор, который инициализирует эти поля при загрузке класса.
Спецификация языка C#
Дополнительные сведения см. в разделах Статические классы и Члены экземпляра и статические члены в документации Предварительная спецификация C# 6.0. Спецификация языка является предписывающим источником информации о синтаксисе и использовании языка C#.
Всем привет. На одном из код-ревью я столкнулся с мыслью, что многие, а чего скрывать и я сам, не то чтобы хорошо понимаем когда нужно использовать ключевое слова static. В данной статье я хотел бы поделиться своими знаниями и информацией по поводу ключевого слова static. Статья будет полезна как начинающим программистам, так и людям, работающим с языком С++. Для понимания статьи у вас должны быть знания о процессе сборки проектов и владение языком С/С++ на базовом уровне. Кстати, static используется не только в С++, но и в С. В этой статье я буду говорить о С++, но имейте в виду, что всё то, что не связано с объектами и классами, в основном применимо и к языку С.
Что такое static?
Где используется?
Ниже приведена схема, как и где используется static в программе.
А теперь я постараюсь детально описать все то, что изображено на схеме. Поехали!
Статические переменные внутри функции
Если не использовать static в строке 4, выделение памяти и инициализация переменной count происходит при каждом вызове функции counter(), и уничтожается каждый раз, когда функция завершается. Но если мы сделаем переменную статической, после инициализации (при первом вызове функции counter()) область видимости count будет до конца функции main(), и переменная будет хранить свое значение между вызовами функции counter().
Статические объекты класса
В строке 3 мы создаем класс Base с конструктором (строка 5) и деструктором (строка 8). При вызове конструктора либо деструктора мы выводим название метода класса в консоль. В строке 14 мы создаем статический объект obj класса Base. Создание этого статического объекта будет происходить только при первом вызове функции foo() в строке 18.
Из-за того, что объект статический, деструктор вызывается не при выходе из функции foo() в строке 15, а только при завершении программы, т.к. статический объект разрушается при завершении программы. Ниже приведен пример той же программы, за исключением того, что наш объект нестатический.
Если мы уберем static при создании переменной в функции foo(), то разрушение объекта будет происходить в строке 15 при каждом вызове функции. В таком случае вывод программы будет вполне ожидаемый для локальной переменной с выделенной памятью на стеке:
Статические члены класса
В сравнении с предыдущими вариантами использования, статические члены класса немного сложнее для понимания. Давайте разберемся, почему. Предположим, у нас есть следующая программа:
В нашем примере мы создали класс А (строка 3) и класс В (строка 9) со статическими членами класса (строка 15). Мы предполагаем, что при создании объекта b в строке 19 будет создан объект a в строке 15. Так бы и произошло, если бы мы использовали нестатические члены класса. Но вывод программы будет следующим:
Причиной такого поведения является то, что статические члены класса не инициализируются с помощью конструктора, поскольку они не зависят от инициализации объекта. Т.е. в строке 15 мы только объявляем объект, а не определяем его, так как определение должно происходить вне класса с помощью оператора разрешения области видимости (::). Давайте определим члены класса B.
Теперь, после того как мы определили наш статический член класса в строке 18, мы можем увидеть следующий результат программы:
Constructor A
Constructor B
Destructor B
Destructor A
Нужно помнить, что член класса будет один для всех экземпляров класса B, т.е. если мы создали три объекта класса B, то конструктор статического члена класса будет вызван только один раз. Вот пример того, о чем я говорю:
Constructor A
Constructor B1
Constructor B2
Constructor B3
Destructor B3
Destructor B2
Destructor B1
Destructor A
Статические функции
Для того чтобы исправить данную проблему, одну из функций мы объявим статической. Например эту:
В этом случае вы говорите компилятору, что доступ к статическим функциям ограничен файлом, в котором они объявлены. И он имеет доступ только к функции sum() из math.cpp файла. Таким образом, используя static для функции, мы можем ограничить область видимости этой функции, и данная функция не будет видна в других файлах, если, конечно, это не заголовочный файл (.h).
Статические функции-члены класса (методы)
Статическую функцию-член вы можете использовать без создания объекта класса. Доступ к статическим функциям осуществляется с использованием имени класса и оператора разрешения области видимости (::). При использовании статической функции-члена есть ограничения, такие как:
В классе A в строке 8 у нас есть статическая функция-член foo(). В строке 14, мы вызываем функцию используя имя класса и оператор разрешения области видимости и получаем следующий результат программы:
Из вывода видно, что никакого создания объекта нет и конструктор/деструктор не вызывается.
Если бы метод foo() был бы нестатическим, то компилятор выдал бы ошибку на выражение в строке 14, т.к. нужно создать объект для того, чтобы получить доступ к его нестатическим методам.
Заключение
В одной статье в интернете я нашел совет от автора – «Используйте static везде, где только можно». Я хотел бы написать, почему так делать не стоит, а стоит использовать только в случае необходимости.
Singleton (Одиночка) или статический класс?
Статья будет полезна в первую очередь разработчикам, которые теряются на собеседованиях когда слышат вопрос «Назовите основные отличия синглтона от статического класса, и когда следует использовать один, а когда другой?». И безусловно будет полезна для тех разработчиков, которые при слове «паттерн» впадают в уныние или просят прекратить выражаться 🙂
Что такое статический класс?
Что такое Singleton (Одиночка)?
Один из порождающих паттернов, впервые описанный «бандой четырех» (GoF). Гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа. Мы не будем подробно рассматривать здесь этот паттерн, его предназначение и решаемые им задачи — в сети существует масса подробной информации о нем (например здесь и здесь). Отмечу лишь что синглтоны бывают потокобезопасные и нет, с простой и отложенной инициализацией.
А если нет разницы — зачем плодить больше?
Так в чем же все-таки разница между этими двумя сущностями и когда следует их использовать? Думаю что лучше всего это проиллюстрировать в следующей таблице:
Singleton | Static class | |
---|---|---|
Количество точек доступа | Одна (и только одна) точка доступа — статическое поле Instance | N (зависит от количества публичных членов класса и методов) |
Наследование классов | Возможно, но не всегда (об этом — ниже) | Невозможно — статические классы не могут быть экземплярными, поскольку нельзя создавать экземпляры объекты статических классов |
Наследование интерфейсов | Возможно, безо всяких ограничений | Невозможно по той же причине, по которой невозможно наследование классов |
Возможность передачи в качестве параметров | Возможно, поскольку Singleton предоставляет реальный объект | Отсутствует |
Контроль времени жизни объекта | Возможно — например, отложенная инициализация (или создание по требованию) | Невозможно по той же причине, по которой невозможно наследование классов |
Использование абстрактной фабрики для создания экземпляра класса | Возможно | Невозможно по причине осутствия самой возможности создания экземпляра |
Сериализация | Возможно | Неприменима по причине отсутствия экземпляра |
Рассмотрим подробнее перечисленные выше критерии.
Количество точек доступа
Конечно же имеются ввиду внешние точки доступа, другими словами — публичный контракт взаимодействия класса и его клиентов. Это удобнее проиллюстрировать с помощью кода:
Singleton в «канонической» реализации:
Наследование классов
С наследованием статических классов все просто — оно просто не поддерживается на уровне языка. С Singleton все несколько сложнее. Для удобства использования многие разработчики чаще всего используют следующую реализацию паттерна:
А поскольку множественное наследование в C# и в любом CLI-совместимом языке запрещено — это означает что мы не сможем унаследовать класс Session от любого другого полезного класса. Выходом является делагирование синглтону управления доступом к экземпляру объекта:
Наследование интерфейсов
Использование интерфейсов позволяет достичь большей гибкости, увеличить количество повторно используемого кода, повысить тестируемость, и, самое главное — избежать сильной связности объектов. Статические классы не поддерживают наследования в принципе. Синглтон, напротив, наследование интерфейсов поддерживает в полной мере, поскольку это обычный класс. Но вот использовать эту возможность стоит только в том случае, если экземпляр синглтона планируется передавать в качестве входных параметров в смешанных сценариях или транслировать за границу домена. Пример смешанного сценария:
Возможность передачи в качестве параметров
Для статических классов это не поддерживается — можно передать разве что тип, но в большинстве ситуаций это бесполезно, за исключением случаев применения механизмов отражения (reflection). Синглтон же по сути является обычным экземпляром объекта:
Контроль времени жизни объекта
Время жизни статического класса ограничено временем жизни домена — если мы создали этот домен вручную, то мы косвенно управляем временем жизни всех его статических типов. Временем жизни синглтона мы можем управлять по нашему желанию. Яркий пример — отложенная инициализация:
Можно также добавить операцию удаления экземпляра синглтона:
Данная операция является крайне небезопасной, поскольку синглтон может хранить некоторое состояние и поэтому его пересоздание может иметь нежелательные последствия для его клиентов. Если все же необходимость в таком методе возникла (что скорее всего указывает на ошибки проектирования) то нужно постараться свести к минимуму возможное зло от его использования — например сделать его закрытым и вызывать внутри свойства Instance при определенных условиях:
Использование абстрактной фабрики для создания экземпляра класса
Статический класс не поддерживает данной возможности ввиду того, что нельзя создать экземпляр статического класса. В случае с синглтоном все выглядит просто:
Правда в варианте с аггрегацией синглтона придеться применить не совсем красивое и, немного громоздкое решение:
Сериализация
Сериализация применима только к экземплярам классов. Статический класс не может иметь экзмпляров поэтому сериализовать в данном случае нечего.
Так что же использовать Синглтон или Статический класс?
В любом случае выбор решения зависит от разработчика и от специфики решаемой им задачи. Но, в любом случае, можно сделать следующие выводы:
BestProg
Статические классы, методы, переменные. Статические конструкторы. Ключевое слово static
Содержание
Поиск на других ресурсах:
1. Какие элементы языка программирования C# можно объявлять статическими?
В языке программирования C# статическими могут быть:
⇑
2. Понятие статического класса. Какие особенности использования статических классов в программах на C#? Ключевое слово static
С точки зрения синтаксиса C# статический класс – это класс, который объявляется с ключевым словом static.
Общая форма объявления статического класса:
где ClassName – имя статического класса.
⇑
3. Свойства статического класса
Реализация программного кода статического класса ничем не отличается от программного кода обычного класса за исключением двух основных свойств. В сравнении с нестатическим классом, статический класс имеет следующие свойства (отличия):
⇑
4. Примеры, которые демонстрируют свойства статического класса
Если попробовать создать объект статического класса
то возникнет ошибка компиляции с сообщением:
то во время компиляции компилятор выдаст следующую ошибку:
⇑
5. Примеры статических классов
Программный код классов Count и Methods следующий:
Если в данном примере класс Count объявить как нестатический (без ключевого слова static )
то результат работы программы не изменится. Статическую переменную Count.count можно использовать как общий ресурс.
Пример 2. Пример демонстрирует использование статического метода в нестатическом классе. Статический метод выступает общим ресурсом, который выполняет некоторую общую работу.
⇑
6. Какие преимущества применения статических классов, методов и переменных в программах на C#?
Статические классы, методы и переменные эффективны в следующих случаях:
⇑
7. Чем отличается вызов статического метода от нестатического?
В любом нестатическом классе могут быть объявлены как статические методы, так и нестатические. Отличие между вызовом статического и нестатического метода класса состоит в следующем:
Ниже демонстрируется вызов и использование этих методов:
Как видно из вышеприведенного кода, чтобы вызвать статический метод некоторого класса, перед его именем нужно указать имя этого класса.
⇑
8. Можно ли объявить скрытый ( private ) статический член в некотором классе?
Да можно. В этом случае этот статический член класса будет доступным только в границах этого класса, то есть из методов этого класса. Доступ из методов других классов будет невозможен.
⇑
Да можно. В этом случае, доступ к статического члену класса будут иметь методы класса, которые унаследованы от данного класса.
⇑
10. Может ли нестатический класс содержать статические переменные и статические методы?
Да может. Примеры использования статических методов в нестатическом классе приведены в пунктах 5 и 7.
⇑
11. Можно ли объединять статические и нестатические методы в одном классе?
Да, можно. Но только в нестатическом классе. Если класс объявлен как статический, то все методы и переменные класса должны быть также статическими (см. п. 4 — Пример 2).
В нижеследующем коде продемонстрирован доступ к скрытой статической переменной t класса CMyClass
Данный пример хорошо демонстрирует, как можно организовать работу с общими, скрытыми данными класса.
⇑
12. Можно ли в статическом методе статического класса создать объект нестатического класса?
⇑
13. Что такое статические конструкторы? Пример
Статические конструкторы позволяют инициализировать статические переменные класса.
Пример. Демонстрируется объявление статического конструктора в классе.
Демонстрация работы класса CCount в некотором методе
⇑
14. Какие правила (особенности) использования статических конструкторов?
При использовании статических конструкторов нужно обратить внимание на следующие правила:
⇑
15. Можно ли из статических конструкторов инициализировать нестатические переменные класса?
Нет, нельзя. Из статических конструкторов можно инициализировать только статические переменные этого же класса. Если в этом классе также объявляются нестатические переменные, то доступа к ним из статических конструкторов нету.
Статические классы
1. Внутренние классы
Недавно вы узнали, что бывают статические переменные и статические методы, но, оказывается, бывают еще и статические классы. Но начнем немного издалека.
В языке Java вполне можно объявлять классы внутри классов. И даже классы внутри классов, которые внутри классов внутри классов. Выглядит это все очень просто:
Просто объявляем один класс внутри другого — и все.
Внутренние классы бывают статические и нестатические. Статические классы еще называют вложенными ( static nested class ), нестатические просто называют внутренними классами ( inner class ).
2. Статические классы
Статические вложенные классы можно использовать вне своего родительского класса. Если у такого класса стоит модификатор доступа public, его можно использовать в любом месте программы. Такие классы фактически ничем не отличаются от любого обычного класса. Хотя есть пара отличий.
Имя класса
Если вы хотите обратиться к статическому вложенному классу не из его класса-родителя, а из другого места в программе, вам нужно будет указать имя класса: оно состоит из имени класса родителя и имени вложенного класса. Общий вид этого имени такой:
Класс родитель | Вложенный класс | Полное имя вложенного класса |
---|
Если вложенный класс имеет свой вложенный класс, их имена просто склеиваются через точку.
Создание объекта
Создать объект вложенного статического класса очень легко. Выглядит это так:
Все, как и с обычными классами, только имя двойное.
Обращение к статическим методам
Если у статического класса есть статические методы, обращаться к ним можно точно так же, как к статическим методам обычных классов (только имя класса теперь двойное).
Обращение к статическим переменным
Обращаться к публичным статическим переменным вложенного класса тоже легко:
3. Особенности статических классов
Статические внутренние классы меньше всего стоило бы называть статическими. Они ведут себя точно так же, как обычные классы. Никаких ограничений на обращение к ним из нестатических методов нет.
Если вы работаете с внутренним статическим классом внутри его класса-родителя, вообще не заметите никакой разницы с тем, если бы этот внутренний класс был бы самым обычным классом (не вложенным и не статическим).
Внутренний статический класс Point | Обычный класс Point |
---|
Если вы возьмете какой-то вложенный статический класс и вынесете его из его класса родителя, все, что изменится, так это то, что новый класс потеряет способность обращаться к private static переменным и методам бывшего класса-родителя.
Внутренний статический класс Point | Обычный класс Point |
---|
Ну а если разобраться, что тут удивительного? Модификатор private прямо говорит, что к переменным и методам, обозначенным этим модификатором, можно обращаться только изнутри их класса. Внутренний статический класс находится внутри класса-родителя? Да, тогда никаких проблем: обращайтесь сколько хотите.