10.2. Поля классов (статические поля)
Как формулирует стандарт языка С#, поле это член класса, который представляет переменную, ассоциированную с объектом или классом. Поле -это объявление данных (константы, переменной, объекта), принадлежащих либо классу в целом, либо каждому из его объектов. Чтобы поле принадлежало не объекту, а классу и могло использоваться до определения объектов этого класса, его объявляют статическим, используя модификатор static. Если в объявлении поля этот модификатор отсутствует, то поле является полем объектов. В этом случае полю выделяется память и оно становится доступным для использования только при и после создания объекта. Статическое поле размещается в памяти в момент загрузки кода класса. Статическое поле (поле класса) доступно для использования и до и после создания объектов класса.
Объявление статистического поля имеет вид;
модификаторыopt static тип_поля список_объявлений;
Индекс opt указывает на необязательность модификаторов отличных от static. В качестве этих необязательных модификаторов поля могут использоваться уже перечисленные модификаторы доступа public, private, protected, internal. Кроме них в объявление поля могут входить (даже без наследования) модификаторы:
readonly запрещает изменять значение поля. Поле получает значение при его инициализации или за счет действий конструктора, и это значение сохраняется постоянно.
volatile - модификатор поля, указывающий, что его значение может измениться независимо от операторов программы. Примером может быть переменная, значение которой сохраняет момент начала выполнения программы. Два последовательных запуска программы приведут к разным значениям этого поля. Второй пример - поле, значение которого в процессе выполнения программы может изменить операционная система или параллельно выполняемый процесс.
Зачастую список объявлений поля содержит только одно объявление. Каждое объявление в списке имеет следующий вид:
идентификатор инициализатор_поляopt
Индекс opt указывает на необязательность инициализатора поля.
Если в объявлении поля отсутствует инициализатор, то инициализация выполняется по умолчанию значением соответствующего типа. В соответствии с общей концепцией типов языка С# поля могут иметь типы ссылок и типы значений. Возможны следующие формы инициализаторов полей:
= выражение
= инициализатор_массива
= new тип (аргументы_конструктора)
В выражение инициализатора, в инициализатор массива и в выражения, используемые в качестве аргументов конструктора, могут входить константы-литералы, а также другие статические члены этого класса.
Нестатические члены невозможно использовать в инициализирующем выражении статического поля.
Пример инициализации и использования статических полей:
// 10_01.cs - статические поля класса
class Lekc10_01
{
class T
{
int x; // поле объектов класса
static int y = 3; // y = х + 5; - ошибка: х - поле объекта
public static int z = 5 - y; // эквивалент: z = 5 - Т.y;
}
public static void Main()
{
//Console.WriteLine("T.y = " + T.y); // Error! T.y is private!
int z = T.z; // z и T.z - разные переменные!
Console.WriteLine("T.z = " + ++T.z); // изменяется T.z
Console.WriteLine("z = {0}", z);
}
}
Результат выполнения программы:
T.z = 3
z = 2
Следует отметить одну особенность инициализации статических полей. Вначале они все получают умалчиваемые значения (для арифметических типов - нулевые). Затем последовательно (сверху вниз) выполняются инициализаторы. Тем самым, если в инициализирующее выражение входит в качестве операнда статическое поле, которое ещё не инициализировано явно, то для него берётся умалчиваемое (например, нулевое) значение. В качестве примера рассмотрим программу:
// 10_02.cs - статические поля класса - порядок инициализации
class Lekc10_02
{
class T
{
public static int x = y;
static int y = 3;
public static int z = y;
}
public static void Main()
{
Console.WriteLine("T.x = " + T.x);
Console.WriteLine("T.z = " + T.z);
}
}
Результат выполнения программы: T.x = 0
T.z = 3
Обратите внимание, что поле у по умолчанию закрытое (имеет статус доступа private) и обращение к нему невозможно вне класса Т.
Открытые статические члены разных классов одной программы могут использоваться в одном выражении. В следующей программе объявлены три класса со статическими полями, обращения к которым используются в инициализирующих выражениях разных классов.
// 10_03.cs - статические поля разных классов
class Lekc10_03
{
class c1
{
public static double orbit = 2 * c2.pi * c3.radius;
}
class c2
{
public static double pi = double.Parse(c3.str);
}
class c3
{
public static string str = "3,14159";
public static double radius = 10;
}
public static void Main()
{
Console.WriteLine("c1.orbit = {0}", c1.orbit);
c3.radius = 20;
Console.WriteLine("c3.radius = {0}", c3.radius);
Console.WriteLine("c1.orbit = {0}", c1.orbit);
}
}
Результат выполнения программы: c1.orbit = 62,8318
с3.radius = 20
c1.orbit = 62,8318
Инициализация статических полей выполняется только однажды. Поэтому значение поля c1.orbit не изменилось после изменения сЗ.radius в методе Main().
