Опубликован: 25.03.2010 | Доступ: свободный | Студентов: 1447 / 158 | Оценка: 4.31 / 4.00 | Длительность: 25:42:00
Лекция 7:

Основы языка C#. Часть 1

< Лекция 6 || Лекция 7: 12345 || Лекция 8 >

Статические члены класса


Применение слова static к членам класса ( или структуры ) устанавливает за этим членом способ адресации только по имени класса, а не по имени экземпляров этого класса. Это значит, что можно использовать данные или метод даже тогда, когда не существует ни одного объекта такого типа.

Статические члены-данные в памяти компьютера занимают только одну постоянную область памяти, которая выделяется для хранения их значений сразу после загрузки программы, в которой есть классы со статическими членами. Предполагается, что их можно обрабатывать и тогда, когда еще не создано ни одного экземпляра. Поэтому и методы, которые должны обрабатывать эти статические данные, также необходимо помечать как статические. Для экземплярных данных создаются свои все новые области памяти с помощью оператора new, и обычные методы, вызываемые по имени объекта, обрабатывают именно данные конкретного экземпляра.

Таким образом, обычные данные-члены и обычные методы вызываются по имени экземпляра, а статические данные и методы вызываются по имени класса.В связи с этим, статические методы не могут использовать обычные поля и обычные методы, ибо последние начинают существовать только после создания экземпляра. Но обычные методы могут использовать статические данные и статические методы, ибо последние начинают существовать сразу после загрузки программы.

Естественно, что статические методы могут иметь внутри себя локальные нестатические переменные (не путайте с полями класса). Для них память выделяется в процессе загрузки метода в стек при его вызове, а освобождается сразу после возвращения из метода.

В одном классе может одновременно объявляться любое количество членов уровня класса и членов уровня экземпляра. Но если в статическом методе попытаться использовать нестатические члены класса (обратится к обычному полю или методу), то компилятор выдаст ошибку.

Приведем пример программы генерации бросков в кости, использующей статические члены класса

using System;
    
class Bones // Игра в кости
{
    // Объявление статического поля
    private static Random rnd = new Random();
    
    // Объявление и определение статических методов
    private static int GetRandomNumber(short maxValue)
    {
        return rnd.Next(maxValue);
    }
        
    public static string Throw()// Бросок 
    {
    string[] messages = new string[6] { "Единица", 
                                        "Двойка", 
                                        "Тройка", 
                                        "Четверка", 
                                        "Пятерка", 
                                        "Шестерка" };
    return messages[GetRandomNumber(6)];
    }
}
    
class Start
{
    static void Main()
    {
        // Выводим броски
        for (int i = 0; i < 10; i++)
            Console.WriteLine("{0}) {1}", i + 1, Bones.Throw());
    
        Console.ReadLine();
    }
}
Листинг 7.9. Генерация бросков нумерованного шестигранного куба на уровне класса

Метод Throw() объявлен статическим и использует вспомогательную функцию GetRandomNumber(), которая в свою очередь использует поле rnd. Поэтому все вспомогательные члены должны быть статическими. Попробуйте убрать слово static из объявления поля rnd или метода GetRandomNumber() - компилятор сразу выдаст ошибку.

Если бы метод Throw() не был объявлен как static, то нужно было бы создать экземпляр класса Bones и вызывать метод на объектном уровне. При этом поле rnd и вспомогательный метод GetRandomNumber() можно оставить статическими

using System;
    
class Bones // Игра в кости
{
    // Объявление статического поля
    private static Random rnd = new Random();
    
    // Объявление и определение статических методов
    private static int GetRandomNumber(short maxValue)
    {
        return rnd.Next(maxValue);
    }
        
    public string Throw()// Бросок 
    {
    string[] messages = new string[6] { "Единица", 
                                        "Двойка", 
                                        "Тройка", 
                                        "Четверка", 
                                        "Пятерка", 
                                        "Шестерка" };
    return messages[GetRandomNumber(6)];
    }
}
    
class Start
{
    static void Main()
    {
        // Создаем экземпляр класса (объект)
        Bones cube = new Bones();
    
        // Выводим броски
        for (int i = 0; i < 10; i++)
            Console.WriteLine("{0}) {1}", i + 1, cube.Throw());
    
        Console.ReadLine();
    }
}
Листинг 7.10. Генерация бросков нумерованного шестигранного куба на уровне объекта

Обе приведенных программы генерируют одинаковый алгоритм. Только в первом случае данные размещаются в самом объекте-типе (там, где размещаются коды методов), а во втором - в объекте-экземпляре типа.

Когда мы моделируем какую-то задачу с помощью класса, то часть параметров этой модели будет общей для всех экземпляров этого класса и ее разумно поместить в отдельную область памяти, доступную всем экземплярам, а не использовать для каждого экземпляра новую память с одинаковым содержимым.

Пусть, например, мы моделируем задачу учета студентов одного факультета. Класс, содержащий данные об одном студенте, будет одновременно иметь индивидуальные для студента характеристики (ФИО, возраст, ...) и общие данные, характерные для студентов одного института и факультета (название, адрес института, учебный корпус). Общие данные удобно сделать статическими и определить их один раз при загрузке программы, после чего они будут доступны всем экземплярам класса студент.

Приведем пример

using System;
    
class Student // Модель одного студента
{
    // Члены уровня класса
    private static string institute = "КИЦМ"; // Институт
    public static void ChangeInstitute(string ins)
    { institute = ins; }
    private static string faculty = "Горный"; // Факультет
    public static void ChangeFaculty(string fac)
    { faculty = fac; }
    
    // Члены объектного уровня
    private string surName; // Фамилия
    private int age, rate;  // Возраст, курс
    
    // Конструктор
    public Student(string surName, int age, int rate)
    {
        this.surName = surName;
        this.age = age;
        this.rate = rate;
    }
    
    // Метод печати всей информации о студенте
    public void Show()
    {
        Console.WriteLine("Студент {0}: ", surName);
        Console.Write("Институт " + institute
                    + ", факультет " + faculty);
        Console.WriteLine(", возраст " + age
                        + ", курс " + rate);
        Console.WriteLine();    // Создание пустой строки
    }
}
    
class Start
{
    static void Main()
    {
        // Настройка консоли
        Console.Title = "Статические и объектные члены";
        Console.ForegroundColor = ConsoleColor.White;
        Console.CursorVisible = false;
    
        // Создаем массив ссылок
        Student[] students = new Student[3];
    
        // Создаем несколько студентов
        students[0] = new Student("Иванов", 18, 1);
        students[1] = new Student("Петров", 19, 2);
        students[2] = new Student("Сидоров", 20, 3);
    
        // Выводим студентов до реорганизации
        Console.WriteLine("Студенты до реорганизации:");
        for (int i = 0; i < students.Length; i++)
            students[i].Show();
    
        // Меняем общее для всех студентов 
        // название института и факультета
        Student.ChangeInstitute("СФУ");
        Student.ChangeFaculty("ФФО");
    
        // Выводим студентов после реорганизации
        Console.WriteLine(Environment.NewLine + "Студенты 
          после реорганизации:");
        for (int i = 0; i < students.Length; i++)
            students[i].Show();
    
        Console.ReadLine();
    }
}
Листинг 7.11. Совместное использование общих и индивидуальных данных

Мы видим, что каждый экземпляр класса использует как общие для всех студентов данные, так и индивидуальные данные для каждого студента. Общие данные хранятся в одной отдельной области памяти, а индивидуальные - в каждом экземпляре студента.

< Лекция 6 || Лекция 7: 12345 || Лекция 8 >
Максим Филатов
Максим Филатов

Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет:

Срок действия этого кода проверки уже истек. Проверьте, правильно ли введен код. У вас осталось две попытки. Вы также можете выбрать другой способ проверки или предоставить соответствующие документы, подтверждающие ваш академический статус.

 

Как активировать код?