C статические. Статические методы в Java(static methods)

В этой статье мы изучим статические методы в Java и сравним Static и Instance. Главное запомнить, что если вы применяете статическое ключевое слово с любым методом, оно называется статическим методом.

Что такое статические методы в Java?

Статические методы — это методы в Java, которые можно вызывать без создания объекта класса. Они задокументированы именем {class the category}.
Статическое ключевое слово может использоваться с классом, переменной, методом и блоком. Статические члены принадлежат классу, а не конкретному экземпляру, это означает, что если вы сделаете член статическим, вы сможете получить к нему доступ без объекта. Давайте рассмотрим пример, чтобы понять это:

Здесь у нас есть статический метод myMethod(), мы можем вызвать этот метод без какого-либо объекта, потому что когда мы делаем член статическим, он становится уровнем класса. Если мы удалим ключевое слово static и сделаем его нестатичным, нам нужно будет создать объект класса для его вызова.

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

Class SimpleStaticExample { // This is a static method static void myMethod() { System.out.println("myMethod"); } public static void main(String args) { /* You can see that we are calling this * method without creating any object. */ myMethod(); } }

Синтаксис

public static void geek(String name) { // code to be executed....

Он хранится в Permanent Generation, поскольку связывается с {class the category}, где они находятся, а не с объектами этого класса. Тем не менее, их локальные переменные, а также передаваемый им аргумент(ы) находятся в стеке.

Важные моменты:

  • Статический метод(ы), связанный с классом, в котором они находятся, то есть они будут ссылаться на него, даже если он не создает экземпляр класса, т.е. ClassName.methodName (args).
  • Они предназначены для совместного использования всеми объектами, созданными из одного класса.
  • Статические методы не могут быть переопределены.

Пример использования статических методов в Java:

Import java.io.*; class Flair{ public static String FlairName = ""; public static void geek(String name) { FlairName = name; } } class GFG { public static void main (String args) { Flair.flair("vaibhav"); System.out.println(Flair.flairName); Flair obj = new Flair (); obj.flair("shadow"); System.out.println(obj.flairName); } }

Вывод:
vaibhav
shadow

Статические переменные(static) и их значения (примитивы или ссылки) определяются внутри класса и хранятся в пространстве памяти PermGen.

Что если статическая переменная ссылается на объект?

static int i = 1;
static Object obj = new Object();

В первой строке значение, которое будет храниться в разделе PermGen. Во второй строке ссылка obj будет храниться в секции PermGen, а объект, на который она ссылается, будет храниться в секции heap.

Когда используются?

  • Если у вас есть код, который может совместно использоваться всеми экземплярами одного и того же класса, поместите эту часть кода в метод Static.
  • В первую очередь настраивайте статические поля доступа к классу.

Что такое метод экземпляра Java?

Метод экземпляра Java — это способы, которыми можно создать объект класса, прежде чем он будет вызываться. Чтобы вызвать метод экземпляра, мы должны сделать объект из категории, в которой он определен.

Public void flair(String name) // code to be {executed.... } // return type can be int, float String or user defined data type.

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

Важные моменты:

  • Инстансы принадлежат объекту класса, а не классу, т. е. они будут также ссылаться, как и после создания объекта класса.
  • Каждый отдельный объект, созданный из {класса, категории}, имеет свою собственную копию метода(ов) экземпляра этого класса.
  • Они могут быть переопределены.

Метод экземпляра или статический метод в Java?

  • Метод экземпляра получит прямой доступ к методам экземпляра и переменным.
  • Метод экземпляра будет обращаться к статическим переменным и статическим методам напрямую.
  • Статические методы будут обращаться к статическим переменным и методам напрямую.
  • Статические методы не могут напрямую обращаться к методам экземпляра и переменным экземпляра. И статический метод не может использовать это, так как нет экземпляра для «this», на который можно сослаться.

Большинство ключевых слов C++ позволяют сделать одну вещь. Вы используете int для объявления целочисленной переменной, или тогда, когда функция возвращает целое значение, или принимает целое число в качестве аргумента. Вы используете оператор new для выделения памяти, а оператор delete — для ее освобождения. Вы можете использовать const для указания, что значение переменной не может быть изменено. По иронии судьбы, ключевое слово static , хотя и означает «неизменный», имеет несколько (и, видимо, не связанных между собой) способов использования. Ключевое слово static может быть использовано в трех основных контекстах:

  • внутри функции;
  • внутри определения класса;
  • перед глобальной переменной внутри файла, составляющего многофайловую программу.

Использование static внутри функции является самым простым. Это просто означает, что после того, как переменная была инициализирована, она остается в памяти до конца программы. Вы можете думать об этом, как о переменной, которая хранит свое значение до полного завершения программы. Например, вы можете использовать статическую переменную для записи количества раз, когда функция была вызвана, просто добавив строки static int count = 0; и count++; в функцию. Так как count является статической переменной, строка static int count = 0; будет выполняться только один раз. Всякий раз, когда функция вызывается, count будет иметь последнее значение, данное ему.

Вы также можете использовать static таким образом, чтобы предотвратить переинициализацию переменной внутри цикла. Например, в следующем коде переменная number_of_times будет равна 100, несмотря на то что строка static int number_of_times = 0; находится внутри цикла, где она, по-видимому, должна исполнятся каждый раз, когда программа доходит до цикла. Хитрость заключается в том, что ключевое слово static препятствует повторной инициализации переменной. Одной из особенностей использования ключевого слова static является то, что оно автоматически устанавливает переменную в ноль для вас — но не полагайтесь на это (это делает ваши намерения неясными).

For(int ix=0; ix < 10; ix++) { for(int iy = 0; iy < 10; iy++) { static int number_of_times = 0; number_of_times++; } }

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

Второе использование static — внутри определения класса. Хотя большинство переменных, объявленных внутри класса могут иметь разное значение в каждом экземпляре класса, статические поля класса будут иметь то же значение для всех экземпляров данного класса и даже не обязательно создавать экземпляр этого класса. Полезно представить себе, что статические переменные класса содержат информацию, необходимую для создания новых объектов (например в фабрике классов). Например, если вы хотите пронумеровать экземпляры класса, можно использовать статическую переменную для отслеживания последнего используемого номера. Важно отметить, что хорошим тоном при использовании статических переменных класса является использование class_name::х; , а не instance_of_class.x; . Это помогает напомнить программисту, что статические переменные не принадлежат к одному экземпляру класса, и что вам не обязательно создавать экземпляр этого класса. Как вы уже, наверное, заметили, для доступа к static можно использовать оператор области видимости, :: , когда вы обращаетесь к нему через имя класса.

Важно иметь в виду, при отладке или реализации программы с использованием static , что вы не можете инициализировать его внутри класса. В самом деле, если вы решите написать весь код класса в файл заголовка, вы даже не сможете инициализировать статическую переменную внутри файла заголовка; сделайте это в файле.cpp . Кроме того, вам необходимо инициализировать статические члены класса, или их не будет в области видимости. (Синтаксис немного странный: type class_name::static_variable = value .)

У вас также могут быть статические функции класса. Статические функции — это функции, которые не требуют экземпляра класса и вызываются так же, по аналогии со статическими переменным, с именем класса, а не с именем объекта. Например, a_class::static_function(); , а не an_instance.function(); . Статические функции могут работать только со статическими членами класса, так как они не относятся к конкретным экземплярам класса. Статические функции могут быть использованы для изменения статических переменных, отслеживать их значения — например, вы можете использовать статическую функцию, если вы решили использовать счетчик, чтобы дать каждому экземпляру класса уникальный идентификатор.

Например, вы можете использовать следующий код:

Class user { private: int id; static int next_id; public: static int next_user_id() { next_id++; return next_id; } // остальные методы для класса user user() // конструктор класса { id = user::next_id++; // или вызов метода, id = user.next_user_id(); } }; int user::next_id = 0;

Обратите внимание, что вы должны включать тип статической переменной, когда вы устанавливаете его!

User a_user;

установит идентификатор на следующий идентификационный номер, не используемый любым другим объектом user . Обратите внимание, что это хороший стиль объявления идентификатора как константы.

Последнее использование static — глобальная переменная в файле кода. В этом случае использование static указывает, что исходный код в других файлах, которые являются частью проекта, не может получить доступ к переменной. Только код внутри того же файла может увидеть переменную (её область видимости ограничена файлом). Эта техника может быть использована для моделирования объектно-ориентированного кода, потому что она ограничивает видимость переменных и таким образом помогает избежать конфликта имен. Этот способ использования static является пережитком Cи.

Кроме модификатора доступа, перед названием поля, метода или свойства можно написать ключевое слово static .
«static » означает, что данное поле, метод или свойство будет принадлежать не каждому объекту класса, а всем им вместе.

Классический пример: как определить, сколько объектов одного класса было создано? Для решения данного вопроса, как раз и служат статические поля и методы .

Давайте разберем на примере с тиграми. Определим класс «Tiger ». Если мы запишем поле класса вот так: public int count; то данное поле будет у каждого объекта, и у каждого объекта оно будет своё. Причем, если не создано ни одного объекта, то это поле не будет существовать вообще.
Поэтому cделаем это поле статическим (static ).

Создадим конструктор, в котором будем увеличить счетчик count при создании каждого нового объекта:
public Tiger() { count++; }.
Здесь же мы можем задавать индивидуальные характеристики тигра: вес, рост, кличка.

Также напишем статический метод, который выводит количество созданных объектов:
public static void ShowNumberOfObjects().

Тогда в нашем консольном приложении будут два класса:

Public class Tiger { public static int count; public Tiger() { count++; } public static void ShowNumberOfObjects() { Console.WriteLine("Тигров = {0}", Tiger.count.ToString()); } } class Program { static void Main(string args) { // Чему равно число тигров без создания объектов? Tiger.ShowNumberOfObjects(); // 0, т.к. мы пока не создали объекты // Создадим 3 тигров Tiger t1 = new Tiger (); Tiger t2 = new Tiger (); Tiger t3 = new Tiger (); Tiger.ShowNumberOfObjects(); // выйдет 3 тигра Console.ReadLine(); } }

Результат: 3.

Вывод. Статический метод позволяет вызывать его, не имея в наличии ни одного объекта. Вместо имени объекта при вызове метода указывается имя класса Tiger: Tiger.ShowNumberOfObjects();

Отличия статического метода от нестатического:

1. Для вызова статического метода не нужен объект.
2. Внутри статического метода недоступна переменная this, указывающая на объект, соответственно недоступны все нестатические поля этого класса, т.к. как нет объекта.
3. Внутри обычного метода доступны как статические, так и нестатические поля.
4. Начиная с C# 4.0 появилась возможность и сам класс сделать статическим.

Иногда создают классы, которые состоят только из статических методов, как, например, класс Math. По сути, такие классы являются контейнерами глобальных функций, однако это отходит от концепции ООП. Также нельзя будет создавать, соответственно, и экземпляры статического класса.

Теперь разберемся с понятием «структура» и выясним ее отличие от класса.

То мы можем получить к ним доступ напрямую через имя класса и оператор разрешения области видимости. Но что, если статические переменные-члены являются закрытыми? Рассмотрим следующий код:

В этом случае мы не можем напрямую получить доступ к Anything::s_value из main(), так как этот член является private. Обычно, доступ к закрытым членам класса осуществляется через методы public. Хотя мы могли бы создать обычный метод для получения доступа к s_value , но нам тогда бы пришлось создавать объект этого класса для использования метода! Есть вариант получше: мы можем сделать метод статическим.

Подобно статическим переменным-членам, статические методы не привязаны к какому-либо одному объекту класса. Вот пример выше, но уже со статическим методом:

class Anything { private: static int s_value; public: static int getValue() { return s_value; } // статический метод }; int Anything::s_value = 3; // определение статической переменной-члена класса int main() { std::cout << Anything::getValue() << "\n"; }

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

Статические методы не имеют указателя *this

У статических методов есть две интересные особенности. Во-первых, поскольку статические методы не привязаны к объекту, то они не имеют ! Здесь есть смысл, так как указатель *this всегда указывает на объект, с которым работает метод. Статические методы могут не работать через объект, поэтому и указатель *this не нужен.

Во-вторых, статические методы могут напрямую обращаться к другим статическим членам (переменным или функциям), но не могут к нестатическим членам. Это связано с тем, что нестатические члены принадлежат объекту класса, а статические методы — нет!

Ещё один пример

Статические методы можно определять вне тела класса. Это работает так же, как и с обычными методами. Например:

#include class IDGenerator { private: static int s_nextID; // объявление статической переменной-члена public: static int getNextID(); // объявление статического метода }; // Определение статической переменной-члена находится вне тела класса. Обратите внимание, мы не используем здесь ключевое слово static // Начинаем генерировать ID с 1 int IDGenerator::s_nextID = 1; // Определение статического метода находится вне тела класса. Обратите внимание, мы не используем здесь ключевое слово static int IDGenerator::getNextID() { return s_nextID++; } int main() { for (int count=0; count < 4; ++count) std::cout << "The next ID is: " << IDGenerator::getNextID() << "\n"; return 0; }

#include

class IDGenerator

private :

static int s_nextID ; // объявление статической переменной-члена

public :

static int getNextID () ; // объявление статического метода

// Начинаем генерировать ID с 1

int IDGenerator :: s_nextID = 1 ;

int IDGenerator :: getNextID () { return s_nextID ++ ; }

int main ()

for (int count = 0 ; count < 4 ; ++ count )

std :: cout << "The next ID is: " << IDGenerator :: getNextID () << "\n" ;

return 0 ;

Результат выполнения программы выше:

The next ID is: 1
The next ID is: 2
The next ID is: 3
The next ID is: 4

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

Предупреждение о классах со всеми статическими членами

Будьте осторожны при написании классов со всеми статическими членами. Хотя такие «чисто статические классы» могут быть полезны, но они также имеют свои недостатки.

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

C++ не поддерживает статические конструкторы

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

Если ваша статическая переменная может быть инициализирована напрямую, то конструктор не нужен: вы можете определить статическую переменную-член, даже если она является private. Мы делаем это в примере выше с s_nextID . Вот ещё один пример:

class Something { public: static std::vector s_mychars; }; std::vector Something::s_mychars = { "o", "a", "u", "i", "e" }; // определяем статическую переменную-член

class Something

public :

static std :: vector < char > s_mychars ;

std :: vector < char > Something :: s_mychars = { "o" , "a" , "u" , "i" , "e" } ; // определяем статическую переменную-член

Если для инициализации вашей статической переменной-члена требуется выполнить код (например, цикл), то есть несколько разных способов это сделать. Следующий способ является лучшим из них:

#include #include class Something { private: static std::vector s_mychars; public: class _nested // определяем вложенный класс с именем _nested { public: _nested() // конструктор _nested инициализирует нашу статическую переменную-член { s_mychars.push_back("o"); s_mychars.push_back("a"); s_mychars.push_back("u"); s_mychars.push_back("i"); s_mychars.push_back("e"); } }; // Статический метод для вывода s_mychars static void getSomething() { for (auto const &element: s_mychars) std::cout << element << " "; } private: static _nested s_initializer; // используем статический объект класса _nested для гарантии того, что конструктор _nested выполнится }; std::vector Something::s_mychars; // определяем нашу статическую переменную-член Something::_nested Something::s_initializer; // определяем наш статический s_initializer, который вызовет конструктор _nested для инициализации s_mychars int main() { Something::getSomething(); return 0; }

#include

#include

class Something

private :

static std :: vector < char > s_mychars ;

public :

class _nested // определяем вложенный класс с именем _nested

public :

Nested () // конструктор _nested инициализирует нашу статическую переменную-член

s_mychars . push_back ("o" ) ;

s_mychars . push_back ("a" ) ;

s_mychars . push_back ("u" ) ;

s_mychars . push_back ("i" ) ;

s_mychars . push_back ("e" ) ;

Последнее обновление: 08.10.2017

Кроме переменных и методов, которые относятся непосредственно к объекту, C++ позволяет определять переменные и методы, которые относятся непосредственно к классу или иначе говоя статические члены класса. Статические переменные и методы относят в целом ко всему классу. Для их определения используется ключевое слово static .

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

#include class Account { public: Account(double sum) { this->sum = sum; } static int getRate() { return rate; } static void setRate(int r) { rate = r; } double getIncome() { return sum + sum * rate / 100; } private: double sum; static int rate; }; int Account::rate = 8; int main() { Account account1(20000); Account account2(50000); Account::setRate(5); // переустанавливаем значение rate std::cout << "Rate: " << Account::getRate() << std::endl; std::cout << "Rate: " << account1.getRate() << " Income: " << account1.getIncome() << std::endl; std::cout << "Rate: " << account2.getRate() << " Income: " << account2.getIncome() << std::endl; return 0; }

В классе Account определена одна статическая переменная rate и две статических функции для управления этой переменной. При определении статических функций стоит учитывать, что внутри них мы можем использовать только статические переменные класса, как например, переменную rate. Нестатические переменные использовать в статических функциях нельзя.

Кроме того, в статических функциях нельзя использовать указатель this, что в принципе и так очевидно, так как this указывает на текущий объект, а статические функции относятся вцелом ко всему классу.

Также важно, что если класс содержит статические переменные, то они должны быть дополнительно определены вне класса:

Int Account::rate = 8;

Присваивать начальное значение переменной необязательно.

Также стоит отметить, что так как статические члены относятся в целом ко всему классу, то для обращения к статическим членам используется имя класса, после которого идет оператор :: . Либо мы можем также обращаться к публичным членам класса через переменные данного класса:

Account::getRate() account1.getRate()

Консольный вывод программы:

Rate: 5 Rate: 5 Income: 21000 Rate: 5 Income: 52500

Также нередко в классах используют статические константы. Например, сделаем в классе Account переменную rate константой:

#include class Account { public: const static int rate = 8; Account(double sum) { this->sum = sum; } double getIncome() { return sum + sum * rate / 100; } private: double sum; }; int main() { Account account1(20000); Account account2(50000); std::cout << "Rate: " << account1.rate << "\tIncome: " << account1.getIncome() << std::endl; std::cout << "Rate: " << account2.rate << "\tIncome: " << account2.getIncome() << std::endl; return 0; }

В отличие от статических переменных статические константы не нужно дополнительно определять вне класса.


Top