Статические переменные

Факты

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

implement example
...
class facts
  myFact_F(string,string).
...
end implement example

В имплементациях динамических классов факты могут быть объявлены либо как статические, либо как динамические:

class example1example1interface
predicates
  запомнитьГород(string Город).
  запомнитьИмяАдрес(string Имя, string Адрес).
  получитьГород()->string Город.
  получитьИмяАдрес(string Имя, string Адрес).
end class example1
 
implement example1
...
class facts
  город_Vstring Город.
...
facts
  имяАдрес_F(string Адрес, string Имя).
 
clauses
  запомнитьГород(Город):-
    город_V:=Город.
...
clauses
  запомнитьИмяАдрес(Имя,Адрес):-
    assert(имяАдрес_F(Адрес,Имя)).
 
clauses
  получитьГород(город_V).
  ...
clauses
  получитьИмяАдрес(Имя,Адрес):-
    имяАдрес_F(Адрес,Имя),
    !,
    ...
end implement example1

В приведенном примере класса example1 факт город_V является статическим, а факты имяАдрес_F(…) являются динамическими, что определяется разницей в имени раздела class facts и просто facts. Поскольку статическая сущность любого класса всего одна, а динамическая — по одной на каждый экземпляр — то и в нашем примере запрос получитьГород(), переданный любому экземпляру, вернет один и тот же результат, а запрос получитьИмяАдрес(…) вернет для каждого экземпляра свое значение.

Особенности использования фактов-переменных

В примере выше использовался факт-переменная город_V, особенностью которого является то, что такой факт всегда один и он сам несет значение терма, объявленного в декларации.

class facts
  город_Vstring Город.

Здесь факт город_V имеет строковое значение. Возможны значения любых объявленных доменов, например

domains
  мойДомен=персона(string Имя,unsigned Возраст).
class facts
  персона_VмойДомен.

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

domains
  мойДомен=персона(string Имя,unsigned Возраст).
class facts
  персона_VмойДомен:=персона("Старик",80).
  город_Vstring:="НеИзвестен".

В динамических классах начальное значение вместо декларации можно задать в клаузе конструктора

implement dynamicClass 
domains
  мойДомен=персона(string Имя,unsigned Возраст).
class facts
  персона_VмойДомен.
clauses
  new():-
     персона_V:=персона("Старик",80),
     ...
end implement dynamicClass

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

class facts
  город_Vstring:=erroneous.

где erroneous — ключевое слово языка. Факт со значением erroneous не может быть использован (точнее: при попытке его использования будет выдана соответствующая ошибка), можно только проверить является ли значение факта неустановленным с помощью детерминированного предиката isErroneous(…)

implement dynamicClass 
domains
  мойДомен=персона(string Имя,unsigned Возраст).
class facts
  город_Vstring:=erroneous.
  персона_VмойДомен.
clauses
  new():-
     персона_V:=персона("Старик",80),
     ...
clauses
  ...
     isErroneous(город_V),
     ...
end implement dynamicClass

С учетом сказанного наш пример

class facts
  город_Vstring Город.

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

пример

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


Статические переменные-члены не считаются определенными внутри класса, только объявлены и, следовательно, имеют свое определение вне определения класса; программисту разрешено, но не требуется, инициализировать статические переменные в их определении. При определении переменных-членов ключевое слово опущено.

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

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

Если статическая переменная-член объявляется но не является и имеет тип интеграла или перечисления, ее можно инициализировать при объявлении внутри определения класса.

C ++ 11

Начиная с C ++ 11, статические переменные- типов (типы, которые могут быть во время компиляции, в соответствии с правилами ) также могут быть объявлены как ; если это так, они должны быть инициализированы в определении класса.

Если или статическая переменная член УСО-используется (неофициально, если он имеет свой адрес Предпринятые или назначается в качестве ссылки), то он должен еще отдельное определение, вне определения класса. Это определение не позволяет содержать инициализатор.

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

Их также можно получить, как если бы они были обычными, нестационарными членами. Это имеет историческое значение, но используется реже, чем оператор области, чтобы предотвратить путаницу в отношении того, является ли элемент статическим или нестационарным.

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

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

Статические члены рассматривают модификаторы доступа, как и нестатические элементы.

Поскольку они не привязаны к данному экземпляру, статические функции-члены не имеют указателя; из-за этого они не могут получить доступ к нестационарным переменным-членам, если не передал экземпляр.

Из-за отсутствия указателя их адреса не могут храниться в указателях-членах-функциях и вместо этого сохраняются в обычных указателях-функциях.

Из — за не имея указатель, они также не могут быть или , они не могут иметь реф-классификаторы. Они также не могут быть виртуальными.

Поскольку они не привязаны к данному экземпляру, статические переменные-члены эффективно рассматриваются как специальные глобальные переменные; они создаются при запуске программы и уничтожаются при ее выходе, независимо от того, существуют ли какие-либо экземпляры класса. Существует только одна копия каждой статической переменной-члена (если только переменная не объявлена (C ++ 11 или новее), в этом случае есть один экземпляр для потока).

Статические переменные-члены имеют ту же связь, что и класс, независимо от того, имеет ли класс внешнюю или внутреннюю связь. Локальным классам и неназванным классам не разрешено иметь статические члены.

Previous Next

A static Class

Java programming language allows us to create a class within a class. It provides a compelling way of grouping elements that are only going to be used in one place, this helps to keep our code more organized and readable.

The nested class architecture is divided into two:

  • nested classes that are declared static are called static nested classes whereas,
  • nested classes that are non-static are called inner classes

The main difference between these two is that the inner classes have access to all member of the enclosing class (including private), whereas the static nested classes only have access to static members of the outer class.

In fact, static nested classes behaved exactly like any other top-level class but enclosed in the only class which will access it, to provide better packaging convenience.

6.1. Example of static Class

The most widely used approach to create singleton objects is through static nested class is it doesn’t require any synchronization and is easy to learn and implement:

6.2. Compelling Reasons to Use a static Inner Class

  • Grouping classes that will be used only in one place increases encapsulation
  • The code is brought closer to the place that will be only one to use it; this increases readability and code is more maintainable
  • If nested class doesn’t require any access to it’s enclosing class instance members, then it’s better to declare it as static because this way, it won’t be coupled to the outer class and hence will be more optimal as they won’t require any heap or stack memory

6.3. Key Points to Remember

  • static nested classes do not have access to any instance members of the enclosing outer class; it can only access them through an object’s reference
  • static nested classes can access all static members of the enclosing class, including private ones
  • Java programming specification doesn’t allow us to declare the top-level class as static; only classes within the classes (nested classes) can be made as static

A static Block

A static block is used for initializing static variables. Although static variables can be initialized directly during declaration, there are situations when we’re required to do the multiline processing.

In such cases, static blocks come in handy.

If static variables require additional, multi-statement logic while initialization, then a static block can be used.

5.1. The static Block Example

Suppose we want to initialize a list object with some pre-defined values.

This becomes easy with static blocks:

In this example, it wouldn’t be possible to initialize List object with all the initial values along with declaration; and that’s why we’ve utilized the static block here.

5.2. Compelling Reasons to Use static Blocks

  • If initialization of static variables requires some additional logic except the assignment
  • If the initialization of static variables is error-prone and requires exception handling

5.3. Key Points to Remember

  • A class can have multiple static blocks
  • static fields and static blocks are resolved and executed in the same order as they are present in the class

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

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

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

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

1 2 3 4 5 6 7

classSomething

{

public

staticstd::vector<char>s_mychars;

};

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

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

#include <iostream> #include <vector>

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’); } };

// Статический метод для вывода s_mychars static void getSomething() { for (auto const &element : s_mychars) std::cout << element << ‘ ‘; } private: static _nested s_initializer; // используем статический объект класса _nested для гарантии того, что конструктор _nested() выполнится }; std::vector<char> Something::s_mychars; // определяем нашу статическую переменную-член Something::_nested Something::s_initializer; // определяем наш статический s_initializer, который вызовет конструктор _nested() для инициализации s_mychars

int main() { Something::getSomething(); return 0; }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38

#include <iostream> #include <vector>  

classSomething


{

private

staticstd::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’);

}

};

// Статический метод для вывода s_mychars

staticvoidgetSomething(){

for(auto const&element s_mychars)

std::cout<<element<<‘ ‘;

}

private

static_nested s_initializer;// используем статический объект класса _nested для гарантии того, что конструктор _nested() выполнится

};

std::vector<char>Something::s_mychars;// определяем нашу статическую переменную-член

Something::_nested Something::s_initializer;// определяем наш статический s_initializer, который вызовет конструктор _nested() для инициализации s_mychars

intmain(){

Something::getSomething();

return;

}

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

При определении статического члена вызовется конструктор по умолчанию _nested() (так как является объектом класса _nested). Мы можем использовать этот конструктор для инициализации любых статических переменных-членов класса Something. Самое крутое здесь — это то, что весь код инициализации скрыт внутри исходного класса со статическим членом.

Константные ссылки и классы

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

На уроке №98 мы рассмотрели преимущества передачи аргументов по константной ссылке, нежели по значению. Если вкратце, то передача аргументов по значению создает копию значения (что является медленным процессом). Большую часть времени нам не нужна копия, а ссылка уже указывает на исходный аргумент и является более эффективной, так как избегает создания и использования ненужной копии. Мы обычно делаем ссылку константной для гарантии того, что функция не изменит значение аргумента и позволит функции работать с  (например, литералами).

Можете ли вы определить, что не так со следующим кодом?

#include <iostream> class Date { private: int m_day; int m_month; int m_year; public: Date(int day, int month, int year) { setDate(day, month, year); } void setDate(int day, int month, int year) { m_day = day; m_month = month; m_year = year; } int getDay() { return m_day; } int getMonth() { return m_month; } int getYear() { return m_year; } }; // Примечание: Мы передаем объект date по константной ссылке, дабы избежать создания копии объекта date void printDate(const Date &date) { std::cout << date.getDay() << «.» << date.getMonth() << «.» << date.getYear() << ‘\n’; } int main() { Date date(12, 11, 2018); printDate(date); return 0; }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40

#include <iostream>

classDate

{

private

intm_day;

intm_month;

intm_year;

public

Date(intday,intmonth,intyear)

{

setDate(day,month,year);

}

voidsetDate(intday,intmonth,intyear)

{

m_day=day;

m_month=month;

m_year=year;

}

intgetDay(){returnm_day;}

intgetMonth(){returnm_month;}

intgetYear(){returnm_year;}

};

// Примечание: Мы передаем объект date по константной ссылке, дабы избежать создания копии объекта date

voidprintDate(constDate&date)

{

std::cout<<date.getDay()<<«.»<<date.getMonth()<<«.»<<date.getYear()<<‘\n’;

}

intmain()

{

Date date(12,11,2018);

printDate(date);

return;

}

Ответ заключается в том, что внутри функции printDate(), объект рассматривается как константный. И через этот константный мы вызываем методы getDay(), getMonth() и getYear(), которые являются неконстантными. Поскольку мы не можем вызывать неконстантные методы через константные объекты, то здесь мы получим ошибку компиляции.

Решение простое — сделать getDay(), getMonth() и getYear() константными:

class Date { private: int m_day; int m_month; int m_year; public: Date(int day, int month, int year) { setDate(day, month, year); } // Метод setDate() не может быть const, так как изменяет значения переменных-членов void setDate(int day, int month, int year) { m_day = day; m_month = month; m_year = year; } // Все следующие геттеры могут быть const int getDay() const { return m_day; } int getMonth() const { return m_month; } int getYear() const { return m_year; } };

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

classDate

{

private

intm_day;

intm_month;

intm_year;

public

Date(intday,intmonth,intyear)

{

setDate(day,month,year);

}

// Метод setDate() не может быть const, так как изменяет значения переменных-членов

voidsetDate(intday,intmonth,intyear)

{

m_day=day;

m_month=month;

m_year=year;

}

// Все следующие геттеры могут быть const

intgetDay()const{returnm_day;}

intgetMonth()const{returnm_month;}

intgetYear()const{returnm_year;}

};

Теперь в функции printDate() константный сможет вызывать getDay(), getMonth() и getYear().

Статические переменные-члены класса

Из урока №51 мы узнали, что статические переменные сохраняют свои значения и не уничтожаются даже после выхода из блока, в котором они объявлены, например:

#include <iostream> int generateID() { static int s_id = 0; return ++s_id; } int main() { std::cout << generateID() << ‘\n’; std::cout << generateID() << ‘\n’; std::cout << generateID() << ‘\n’; return 0; }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

#include <iostream>

intgenerateID()

{

staticints_id=;

return++s_id;

}

intmain()


{

std::cout<<generateID()<<‘\n’;

std::cout<<generateID()<<‘\n’;

std::cout<<generateID()<<‘\n’;

return;

}

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

Обратите внимание, сохраняет свое значение после каждого вызова функции generateID(). Ключевое слово static имеет другое значение, когда речь идет о глобальных переменных — оно предоставляет им внутреннюю связь (что ограничивает их видимость/использование за пределами файла, в котором они определены)

Поскольку использование глобальных переменных — это зло, то ключевое слово static в этом контексте используется не очень часто

Ключевое слово static имеет другое значение, когда речь идет о глобальных переменных — оно предоставляет им внутреннюю связь (что ограничивает их видимость/использование за пределами файла, в котором они определены). Поскольку использование глобальных переменных — это зло, то ключевое слово static в этом контексте используется не очень часто.

В языке C++ ключевое слово static можно использовать в классах: статические переменные-члены и статические методы. Мы поговорим о статических переменных-членах на этом уроке, а о статических методах на следующем.

Прежде чем мы перейдем к ключевому слову static с переменными-членами класса, давайте сначала рассмотрим следующий класс:

#include <iostream>

class Anything { public: int m_value = 3; }; int main() { Anything first; Anything second; first.m_value = 4; std::cout << first.m_value << ‘\n’; std::cout << second.m_value << ‘\n’; return 0; }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

#include <iostream>  

classAnything

{

public

intm_value=3;

};

intmain()

{

Anything first;

Anything second;

first.m_value=4;

std::cout<<first.m_value<<‘\n’;

std::cout<<second.m_value<<‘\n’;

return;

}

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

Переменные-члены класса можно сделать статическими, используя ключевое слово static. В отличие от обычных переменных-членов, статические переменные-члены являются общими для всех объектов класса. Рассмотрим следующую программу:

#include <iostream>

class Anything { public: static int s_value; }; int Anything::s_value = 3; int main() { Anything first; Anything second; first.s_value = 4; std::cout << first.s_value << ‘\n’; std::cout << second.s_value << ‘\n’; return 0; }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21

#include <iostream>  

classAnything

{

public

staticints_value;

};

intAnything::s_value=3;

intmain()

{

Anything first;

Anything second;

first.s_value=4;

std::cout<<first.s_value<<‘\n’;

std::cout<<second.s_value<<‘\n’;

return;

}

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

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

Константы, поля и структуры для чтения

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

Полями класса называются обычные переменные уровня класса. Мы уже ранее рассматривали переменные — их объявление и инициализацию. Однако некоторые моменты мы еще не затрагивали, например, константы и поля для чтения.

Константы

Константы характеризуются следующими признаками:

  • Константа должна быть проинициализирована при определении

  • После определения значение константы не может быть изменено

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

const double PI = 3.14;
const double E = 2.71;

При использовании констант надо помнить, что объявить мы их можем только один раз и что к моменту компиляции они должны быть определены.

class MathLib
{
    public const double PI=3.141;
    public const double E = 2.81;
	public const double K;		// Ошибка, константа не инициализирована
}

class Program
{
    static void Main(string[] args)
    {
        MathLib.E=3.8; // Ошибка, значение константы нельзя изменить
    }
}

Также обратите внимание на синтаксис обращения к константе. Так как неявно это статическое поле, для обращения к ней необходимо использовать имя класса

class MathLib
{
    public const double PI=3.141;
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(MathLib.PI);
    }
}

Но следует учитывать, что мы не можем объявить константу с модификатором static. Но в этом собственно и нет смысла.

Константу можно определить как на уровне класса, так и внутри метода:

class MathLib
{
	public double GetCircleArea(double radius)
	{
		const double PI = 3.141;
		return PI * radius * radius;
	}
}

Поля для чтения

Поля для чтения можно инициализировать при их объявлении либо на уровне класса, либо инициилизировать и изменять в конструкторе. Инициализировать или изменять их значение в других местах нельзя, можно только считывать их значение.


Поле для чтения объявляется с ключевым словом readonly:

class MathLib
{
    public readonly double K = 23;	// можно так инициализировать

    public MathLib(double _k)
    {
        K = _k; // поле для чтения может быть инициализировано или изменено в конструкторе после компиляции
	}
	public void ChangeField()
    {
        // так нельзя
        //K = 34;
    }
}

class Program
{
    static void Main(string[] args)
    {
        MathLib mathLib = new MathLib(3.8);
        Console.WriteLine(mathLib.K); // 3.8

		//mathLib.K = 7.6; // поле для чтения нельзя установить вне своего класса
        Console.ReadLine();

    }
}

Сравнение констант

  • Константы должны быть определены во время компиляции, а поля для чтения могут быть определены во время выполнения программы.

    Соответственно инициализировать константу можно устанновить только при ее определении.

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

  • Константы не могут использовать модификатор static, так как уже неявно являются статическими. Поля для чтения могут быть как статическими, так и не статическими.

Структуры для чтения

Кроме полей для чтения в C# можно определять структуры для чтения. Для этого они предваряются модификатором readonly:

readonly struct User { }

Особенностью таких структур является то, что все их поля должны быть также полями для чтения:

readonly struct User
{
	public readonly string name;
	public User(string name)
	{
		this.name = name;
	}
}

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

readonly struct User
{
	public readonly string Name { get; } // указывать readonly необязательно
	public int Age { get; } // свойство только для чтения
	public User(string name, int age)
	{
		this.Name = name;
		this.Age = age;
	}
}

НазадВперед

The static Methods (Or Class Methods)

Similar to static fields, static methods also belong to a class instead of the object, and so they can be called without creating the object of the class in which they reside. They’re meant to be used without creating objects of the class.

4.1. Example of static Method

static methods are generally used to perform an operation that is not dependent upon instance creation.

If there is a code that is supposed to be shared across all instances of that class, then write that code in a static method:

static methods are also widely used to create utility or helper classes so that they can be obtained without creating a new object of these classes.

Just take a look at Collections or Math utility classes from JDK, StringUtils from Apache or CollectionUtils from Spring framework and notice that all methods are static.

4.2. Compelling Reasons to Use static Methods

  • To access/manipulate static variables and other static methods that don’t depend upon objects
  • static methods are widely used in utility and helper classes

4.3. Key Points to Remember

  • static methods in Java are resolved at compile time. Since method overriding is part of Runtime Polymorphism, so static methods can’t be overridden
  • abstract methods can’t be static
  • static methods cannot use this or super keywords
  • The following combinations of the instance, class methods and variables are valid:
    1. Instance methods can directly access both instance methods and instance variables
    2. Instance methods can also access static variables and static methods directly
    3. static methods can access all static variables and other static methods
    4. static methods cannot access instance variables and instance methods directly; they need some object reference to do so

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

У статических методов есть две интересные особенности.

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

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

The static Fields (Or Class Variables)

In Java, if a field is declared static, then exactly a single copy of that field is created and shared among all instances of that class. It doesn’t matter how many times we initialize a class; there will always be only one copy of static field belonging to it. The value of this static field will be shared across all object of either same of any different class.

From the memory perspective, static variables go in a particular pool in JVM memory called Metaspace (before Java 8, this pool was called Permanent Generation or PermGen, which was completely removed and replaced with Metaspace).

3.1. Example of the static Field

Suppose we have a Car class with several attributes (instance variables). Whenever new objects are initialized from this Car blueprint, each new object will have its distinct copy of these instance variables.

However, suppose we are looking for a variable that holds the count of the number of Car objects that are initialized and is shared across all instances such that they can access it and increment it upon their initialization.

That’s where static variables come in:

Now for every object of this class that gets initialized, the same copy of the numberOfCars variable is incremented. So for this case, the following assertions will be true:

3.3. Key Points to Remember

  • Since static variables belong to a class, they can be accessed directly using class name and don’t need any object reference
  • static variables can only be declared at the class level
  • static fields can be accessed without object initialization
  • Although we can access static fields using an object reference (like ford.numberOfCars++) , we should refrain from using it as in this case it becomes difficult to figure whether it’s an instance variable or a class variable; instead, we should always refer to static variables using class name (for example, in this case, Car.numberOfCars++)

Static Variables

In Java, when we create objects of a class, then every object will have its own copy of all the variables of the class. For example,

Here, both the objects test1 and test2 will have separate copies of the variable age. And, they are different from each other.

However, if we declare a variable static, all objects of the class share the same static variable. It is because like static methods, static variables are also associated with the class. And, we don’t need to create objects of the class to access the static variables. For example,

Here, we can see that we are accessing the static variable from the other class using the class name.

Example 2: Java static and non-static Variables

Output:

min + 1 = 6
max + 1 = 11

In the above program, we have declared a non-static variable named min and a static variable named max inside the class Test.

Inside the Main class, we can see that we are calling the non-static variable using the object of the class (). However, we are calling the static variable by using the class name ().

Note: Static variables are rarely used in Java. Instead, the static constants are used. These static constants are defined by keyword and represented in uppercase. This is why some people prefer to use uppercase for static variables as well.

Static Methods

Static methods are also called class methods. It is because a static method belongs to the class rather than the object of a class.

And we can invoke static methods directly using the class name. For example,

Here, we can see that the static method can be accessed directly from other classes using the class name.

In every Java program, we have declared the method . It is because to run the program the JVM should be able to invoke the main method during the initial phase where no objects exist in the memory.

Example 1: Java static and non-static Methods

Output:

2 * 2 = 4
2 + 3 = 5

In the above program, we have declared a non-static method named and a static method named inside the class .

Inside the Main class, we can see that we are calling the non-static method using the object of the class (). However, we are calling the static method by using the class name ().


С этим читают