Показаны сообщения с ярлыком static. Показать все сообщения
Показаны сообщения с ярлыком static. Показать все сообщения

17 авг. 2015 г.

Внутренние классы. Часть 2 – статические вложенные классы.

Статические вложенные классы (nested) очень похожи на классы верхнего уровня. Их обычно используют если необходимо логически связать два класса – внешний и внутренний. Интерфейсы так же могут быть статическими вложенными интерфейсами располагающимися внутри внешнего класса или интерфейса.

Статический вложенный класс определяется внутри другого внешнего класса. Это может выглядеть так:

NC0001

Как видно из кода, внешним классом является класс OuterClass, статическим вложенным классом является StaticNesterdClass, статическим вложенным интерфейсом является StaticNestedInterface.

Обратите внимание на границы внешнего класса, а так же вложенного статического класса и интерфейса.

По существу внешний класс для статического вложенного класса является как бы мини пакетом.

 

Статический вложенный класс или интерфейс определен как static член окружающего класса, что делает его аналогом поля и метода класса, которые так же объявлены как static. Как и метод класса, статический вложенный класс не связан ни с одним экземпляром внешнего класса, то есть может использоваться без создания экземпляра внешнего класса. Тем не менее статический вложенный класс имеет доступ ко всем static членам окружающего класса, включая любые другие статические вложенные классы и интерфейсы. Статический вложенный класс может использовать любой статический член окружающего класса без указания имени этого окружающего класса.

Статический вложенный класс имеет доступ ко всем статическим членам окружающего класса, включая private члены. Обратное тоже верно: методы окружающего класса имеют доступ ко всем static членам статического вложенного класса, включая его private static члены, однако при обращении к ним необходимо указывать имя статического вложенного класса, которому они принадлежат.

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

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

Из статических вложенных классов вы не можете обращаться к нестатическим членам внешнего класса. Обратное тоже верно – из внешних классов вы не можете обращаться к нестатическим членам вложенного статического класса. Статический вложенный класс для доступа к нестатическим членам и методам внешнего класса должен создавать его объект. Обратное так же верно – для доступа к нестатическим членам вложенного класса, внешний должен создать его объект.

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

Ну и теперь немного практики…

NC0002

NC0003

NC0004

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

nst.getName() выводит private поле nestedName. Заметьте что оно не статическое и private. nst.getOuterName() выводит статическое private поле outerName внешнего класса Outer. Далее выводиться статическое поле out внешнего класса Outer. Мы смогли это сделать так как оно статическое. Далее выводится статическое поле nst вложенного класса Nested через уточнение именем класса Outer.

Затем мы создаем экземпляр класса Outer и получаем через него доступ к private static полю outerName через вызов метода getName() на экземпляре класса Outer. И последняя строка выводит private static поле вложенного класса через метод внешнего класса getStnst(), который имеет доступ даже к private static полям вложенного класса. Ну как не запутались? :) По идее пока все не очень сложно :)

NC0005

Ну и еще стоит отметить, что компилятор все равно нам создал три .class файла. Но вложенный класс Nested создан с уточняющим именем внешнего класса Outer через знак $. Поэтому все вложенные классы являются чистым синтаксическим сахарком, но достаточно нужным и удобным.

В коде, расположенном вне окружающего класса, на статический вложенный класс или интерфейс ссылаются по имени внешнего класса с последующим добавлением имени внутреннего класса (например, Outer.Nested). Для импорта статических классов-членов можно применять директиву import:

import pro.java.nested.Outer.Nested; // импорт вложенного класса Nested
import pro.java.nested.Outer.*; // импорт всех вложенных классов из класса Outer

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

Nested nst = new Nested("MyNested");

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

Outer.Nested nst = new Outer.Nested("MyNested");

 

NC0007Теперь еще немного поговорим о вложенных интерфейсах. Я добавил в класс Outer вложенный интерфейс IGetNames и вложенный класс GetNames в котором реализовал этот интерфейс, а так же в класс Main добавил создание экземпляра класса GetNames и использование его методов.

NC0008

Здесь я привел лишь отрывки кода который был добавлен. В этом примере класс GetNames является вложенным в класс Outer, но ни что не мешает вложить его в интерфейс IGetNames.

 

Но тогда уже придется уточнять имя класса вложенного в интерфейс через имя внешнего класса и имя вложенного интерфейса:

Outer.IGetNames.GetNames gn = new Outer.IGetNames.GetNames();

NC0009

Для наглядности, так же приведу отрывки измененного кода в классе Outer. в классе Main была изменена лишь строка создания экземпляра класса GetNames, которая уже была приведена выше.

Оба два предыдущих примера генерируют следующий вывод:

NC0010

Три последние строки генерируются вызовом методов на экземпляре класса GetNames.

Вызов этих методов приведен на отрывке кода представленного на скриншоте выше.

Интересно так же посмотреть на те .class файлы которые получились в результате наших изменений в коде классов.

NC0011

Как видим у нас получилось пять .class файлов. По одному на каждый из наших классов и интерфейсу. Особое внимание следует обратить на имена вложенных классов и интерфейса. Уровень вложенности классов разделяется знаком $. Знак доллара является валидным символов в именах классов, но предназначен для использования только компилятором и JVM.

Кстати сказать избавиться от длинной строки создания экземпляра класса GetNames можно все тем же импортом. Для этого нам надо импортировать этот класс по его полному имени:

import pro.java.nested.Outer.IGetNames.GetNames;

Тогда строка создания экземпляра класса GetNames будет выглядеть так:

GetNames gn = new GetNames();

Но опять же тут не очевидно что GetNames это вложенный класс, хотя эта запись гораздо короче.

NC0012Вложенные классы можно размещать и просто в интерфейсах. Любой класс, помещенный в интерфейс, автоматически объявляется как открытый (public) и статический (static). Так как класс объявляется как static, он не нарушает правил обращения с интерфейсом – этот вложенный класс всего лишь размещается в пространстве имен интерфейса. И как я уже показывал, вы даже можете реализовать окружающий интерфейс во внутреннем классе. Хитрый пример показан слева. И если вы его просто попробуете запустить из Eclipse, то ни чего не выйдет, хотя этот файл без проблем и ошибок скомпилируется. И он даже работает и его даже можно запустить, но используя магию правильное понимание. Это понимание можно почерпнуть здесь. Но все же его стоит чуть обновить до нынешних наших знаний.

И поможет нам в этом магия утилиты javap

NC0013

То есть нам надо запускать класс содержащий метод main() по его полному имени и делать это правильным образом из правильного места.

NC0014

Но можно сделать это и из Eclipse указав класс где находится метод main():

NC0015

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

Статические вложенные классы можно так же использовать для проверки работоспособности классов, то есть для их тестирования. Поскольку в них вы можете расположить метод main(). Как вы уже знаете при компиляции будет скомпилирован отдельный .class файл для вложенного класса, который вы можете запускать для тестирования работы отдельного класса не запуская всю программу. Кроме того, в окончательную сборку программы можно не включать файлы .class которые были сгенерированы для тестирования, их можно просто удалить и собрать программу, таким образом в ней не будет лишнего кода, который вы создали для тестирования.

NC0017

NC0016

На примерах слева и сверху представлены два класса Main, содержащий метод main() и SomeClass, содержащий вложенный класс Test, который так же содержит метод main().

После компиляции получается соответственно три файла с расширением .class:

NC0018

Если посмотреть на содержимое файлов SomeClass.class и SomeClass$Test.class при помощи javap, то увидим следующее:

NC0019

Как видим в байт коде класса SomeClass не присутствует код вложенного в него класса Test, поскольку он находится в отдельном своем .class файле, в котором есть метод main(). И этот .class файл мы можем запустить отдельно от класса Main. Так же мы можем запустить на исполнение и класс Main, и даже если мы удалим откомпилированный .class файл класса Test, то наша программа все равно будет работать правильно.

NC0020

В дополнение ко всему вышесказанному предлагаю посмотреть хорошее видео по вложенным статическим классам:

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

NC0021

NC0022

Что тут стоить отметить, так это то что в классе Human, а так же в его вложенном классе Relations используется идентификатор relations во множестве мест и при этом не происходит ни какой путаницы. Кроме того, в отличие от примера на видео, я сперва создал объект статического вложенного класса, а уже только потом создал объект внешнего класса, чтобы подчеркнуть независимость одного от другого.

Теперь еще стоит поговорить о наследовании в статических вложенных классах.

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

И теперь опять попрактикуемся…

NC0023

NC0024

Вывод у программы следующий:

NC0025

Как видим в этом примере у нас есть два класса наследника вложенного класса Nested. Это классы Ext1 и Ext2. Причем Ext1 является внутренним классом для класса Nested и соответственно имеет доступ ко всем полям внешнего класса Outer. Обращаю внимание что класс Ext1 не статический, а внутренний, то есть inner (это наша следующая тема). Класс же Ext2 не является внутренним классом Nested хотя и наследует его и поэтому он не имеет доступа к полям класса Nested. Следует обратить внимание на интересный синтаксис создания экземпляра класса Ext1. Поскольку класс Ext1 не статический, то он не может быть создан без привязки к экземпляру его внешнего класса.

Если же класс Ext1 сделать статическим, то строка создания его экземпляра будет выглядеть для нас уже привычным образом:

Outer.Nested.Ext1 ext1 = new Outer.Nested.Ext1();

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

Можно так же привести примеры использования статических вложенных классов из реальной жизни. Что может быть более реального чем стандартная библиотека java в которой существует класс java.awt.geom.Rectangle2D который имеет два вложенных класса, Float и Double. Это очень простые классы форм и было бы просто ни к чему умножать количество высокоуровневых классов в этом пакете еще на два.

NC0026

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

NC0027

NC0028

Тут представлен окончательный вариант с реализацией интерфейса IStack двумя классами FixedStack и DynStack. Причем класс DynStack является вложенным в класс FixedStack, который в свою очередь вложен в интерфейс IStack. Класс DynStack наследуется от класса FixedStack и поэтому там переопределен только один метод push(), который увеличивает размер стека в два раза при его заполнении.

Стоит обратить внимание на то что для класса FixedStack мы не писали слово static, хотя он таковым и является поскольку является вложенным в интерфейс классом. А вот для класса DynStack нам уже пришлось написать слово static, так как если бы мы этого не сделали, то этот класс был бы внутренним, то есть inner – не статическим.

Ну и на последок длинная портянка вывода данной программы:

NC0029

Первая строка выводится сразу же после создания объекта fix. Тогда еще стек пустой.

Затем мы добавили в стек единицу и вывели его состояние.

После добавили строку и опять вывели состояние.

Затем добавили значение типа double 55.55 и вывели состояние.

Затем попытались добавить ссылку null, что вполне легитимно для Object, но нам выдалось сообщение что стек полон.

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

После этого напечатали звездочки и создали объект динамического стека.

Добавили туда 10 вывели значение.

Добавили другую строку и снова вывели значение.

Затем добавили туда значение 77.77, но поскольку стек у нас был из двух элементов, то произошло увеличение размера стека, о чем мы и получили сообщение и уже в увеличенные стек было помещено значение 77.77 что мы и видим в выводе программы.

После этого значение 77.77 было изъято из стека и содержимое стека было выведено на экран.

За сим все! Кино про статические вложенные классы закончено :)

Далее в программе изучение внутренних inner классов.

Да и вообще далее еще много чего :)

13 авг. 2015 г.

Внутренние классы. Часть 1 – введение.

Все классы, которые мы рассматривали до сих пор являлись классами верхнего уровня (то есть они являлись непосредственными членами пакетов и не были вложены в другие классы). В интерфейсах, мы кратко рассмотрели тему вложенных интерфейсов. В Java есть четыре типа классов, именуемых внутренними или вложенными классами (inner or nested classes), которые могут быть определены в Java программе.

Примечание: Программисты, пишущие на Java, не пришли к единому мнению по поводу именования различных типов внутренних классов. Поэтому вы можете обнаружить, что в разных ситуациях их называют поразному. Например статические внутренние классы иногда называют вложенными – nested, а простые внутренние классы – inner. По крайней мере так они определяются в оригинальной документации, а так же многих книгах и руководствах.

Terminology: Nested classes are divided into two categories: static and non-static. Nested classes that are declared static are called static nested classes. Non-static nested classes are called inner classes.

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

Внутренние классы являются элегантным и мощным инструментом языка Java. Эти четыре типа классов представлены ниже:

Статические вложенные классы (static nested classes)

Статический вложенный класс – это класс (или интерфейс), определенный как static внутри другого класса. Метод с модификатором static называют методом класса, поэтому внутренний класс такого типа можно назвать «классом класса», но подобная терминология была бы очень запутанной. Статические вложенные классы ведут себя почти так же, как обычные классы верхнего уровня, за исключением того, что они могут получать доступ к static членам класса, в котором они содержатся. Интерфейсы так же могут быть определены как статические внутренние члены классов.

Внутренние классы (inner classes)

Внутренний класс определяется внутри окружающего класса, но он объявляется без модификатора static. Этот тип внутренних классов является аналогом методов и полей экземпляра. Экземпляр внутреннего класса всегда связан с экземпляром окружающего класса, а код внутреннего класса имеет доступ ко всем полям и методам (как статическим, так и нестатическим) окружающего класса. Есть несколько особенностей синтаксиса языка Java, проявляющихся при работе с экземпляром класса, содержащего внутренний класс. Интерфейсы могут быть определены только как статические члены, но не как нестатические.

Локальные классы (local classes)

Локальный класс – это класс, определенный в блоке Java-кода. Как и локальная переменная, локальный класс виден только внутри блока. Локальным классам присущи многие особенности внутренних классов. Кроме того, локальные классы могут работать с любыми final переменными или параметрами, которые доступны в блоке, где класс был определен. Интерфейсы нельзя определить локально.

Анонимные классы (anonymous classes)

Анонимный класс – это вид локального класса без имени; он комбинирует синтаксис для объявления класса с синтаксисом для присвоения значения объекту. Объявление локального класса – это оператор Java, а определение анонимного класса (и присвоение значения) – это выражение Java, поэтому такое определение может появляться только как часть еще большего выражения, например вызова метода. Интерфейсы нельзя определить анонимно.

Так же тут стоит упомянуть о том, что можно определить несколько классов верхнего уровня в одном файле .java. Такие классы не являются ни одним из типов внутренних классов. По существу это равнозначно что для каждого класса создается отдельный файл .java. Но если один .java файл содержит несколько классов верхнего уровня, только один из них может быть объявлен как public, остальные должны быть с пакетным доступом. И по имени класса public должен называться .java файл. Мы уже с этим встречались во множестве прошлых примеров кода, а тут я просто описал правило для этого случая. Обычно это используется для небольших тестовых или учебных программ, ну или для логической группировки связанных классов. Каждый класс верхнего уровня, который содержится в .java файле компилируется в отдельный .class файл с именем компилируемого класса. Приведу небольшой пример:

in01

Обратите внимание на подсветку скобок которые определяют границы класса Main. Класс Example не входит в эти границы и поэтому не является вложенным классом.

Если посмотреть на то файлы что сгенерировал компилятор, то мы увидим следующую картину:

in02

Далее уже будем рассматривать внутренние классы.

17 июл. 2015 г.

Интерфейсы. Часть 5 – вложенные интерфейсы.

Интерфейс может быть объявлен членом класса или другого интерфейса. Такой интерфейс называется интерфейсом-членом или вложенным интерфейсом. Вложенный в класс интерфейс может быть объявлен как public, private или protected. Это отличает его от интерфейса верхнего уровня или интерфейса вложенного в другой интерфейс, который должен быть либо объявлен как public, либо, как уже было отмечено, должен использовать уровень доступа, заданный по умолчанию.

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

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

Ну и небольшой примерчик, который демонстрирует все вышеописанное…

Вывод у программы следующий:

I0023

Первая строка выводится статическим методом aintPrt2() вложенного в класс А интерфейса Aint1. Вывод генерирует строка 80. Вторая строка выводится при помощи некоторый танцев с бубном, а именно при помощи метода AaPrint() вложенного класса Aa. Вложенные классы мы пока не изучали, поэтому данный бубен может быт не понятен. Далее уже все просто :) ну и по правде сказать лень расписывать подробно. Если чё, то пишите комменты :)

Интерфейсы. Часть 4 – статические методы.

Начиная с версии JDK 8, у интерфейсов появилась еще одна возможность: определять в нем один или несколько статических методов. Аналогично статическим методам в классе, метод, объявляемый как static в интерфейсе, можно вызывать независимо от любого объекта. Для этого метод должен быть определен в интерфейсе. Для вызова статического метода достаточно указать имя интерфейса и через точку имя самого метода. Ниже приведена общая форма вызова статического метода из интерфейса. Обратите внимание на ее сходство с формой вызова статического метода из класса.

имя_интерфейса.имя_статического_метода

Статические методы из интерфейсов не наследуются ни реализующими их классами, ни интерфейсами наследниками.

I0020

Как видим на примере слева в интерфейсе MyInt определен статический метод prt1() с реализацией, а так же объявлен метод prt2() без реализации.

Так же мы создали класс Prt, который имплементирует интерфейс MyInt, но он не унаследовал метод prt1(), так как он является статическим.

Класс Interf01 у нас так же реализует интерфейс MyInt и кроме того он содержит метод main(). Поскольку он реализует интерфейс MyInt, так же возникла необходимость определения метода prt2().

Этот метод prt2() не является статическим и поэтому его без танцев с бубном из статического метода main() вызвать нельзя.

Танцы с бубном продемонстрированы в последних двух строках метода main().

Вывод у программы следующий:

I0021 

Первая строка выводится вызовом статического метода prt1() на интерфейсе. Вторая строка выводится вызовом метода prt2() на экземпляре класса Prt, а третья на экземпляре класса Interf01.

29 июн. 2015 г.

Классы. Часть 11 – раскрываем тайну System.out.println()

Этот пост можно назвать небольшой практикой, которая может показать нам, что мы уже знаем в чем же тайна System.out.println(). Мы сейчас практически повторим эту же конструкцию сами. Тут просто приведу код двух классов, которые реализуют эту конструкцию и ее применение в третьем.

N0037

N0038

N0039

В Classes011 мы просто используем класс Syst в котором определена статическая переменная (ссылка) out ссылающаяся на класс PrtStr, в котором есть метод print().

Хотя, конечно же, в классе System все это реализовано немного по другому, но принцип остается тот же.

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

26 июн. 2015 г.

Классы. Часть 10 – инициализация полей класса.

Мы уже видели как можно присваивать значения полям класса. Но чтобы подвести итог перечислим их:

  • Инициализация значениями по умолчанию
  • Инициализация при объявлении поля
  • Инициализация через конструктор
  • Инициализация в инициализационном блоке

Первые три способа мы уже видели, теперь рассмотрим четвертый.

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

Ну и теперь примеры…

N0034

N0035

Вывод у программы следующий:

N0036

Инициализационные блоки выполняются в порядке их следования в объявлении класса.

В этой программе продемонстрированы все четыре способа инициализации полей.

25 июн. 2015 г.

Классы. Часть 9 – модификатор static для полей и методов.

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

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

Как уже обсуждалось, класс – это коллекция данных, хранимых в именованных полях, и кода, организованного в именованные методы, оперирующие этими данными. Поля и методы называются членами класса (members). В Java классы могут содержать другие классы. Эти классы-члены, или внутренние классы, предоставляют дополнительную функциональность которую мы обсудим чуть позже. Сейчас мы рассмотрим только поля и методы. Члены класса делятся на два различных типа: члены класса, связанные непосредственно с классом (статические), и члены экземпляра, связанные с каждым экземпляром класса (то есть с объектом). Не принимая во внимание классы-члены, мы получаем четыре типа членов:

  • Поля класса (статические поля – static fields)
  • Методы класса (статические методы – static methods)
  • Поля экземпляра (instance fields)
  • Методы экземпляра (instance methods)

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

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

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

Статические поля и методы объявляются при помощи модификатора static.

На методы, объявленные как static, накладывается ряд ограничений:

  • Они могут вызывать только другие статические методы.
  • Они могут получать доступ только к статическим переменным.
  • Они ни коим образом не могут ссылаться на члены типа this или super. (Ключевое слово super связано с наследованием и будет рассмотрено чуть позже)
  • Статические методы не могут быть абстрактными
  • Статические методы переопределяются в подклассах только как статические
  • При переопределении статических методов полиморфизм не действует, ссылки всегда направляются на методы класса, а не объекта

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

Ну и теперь немного попрактикуемся… Вернемся к нашим баранам коровам…

N0029

N0030

Как видно в классе Cow мы определили статическую переменную count, а так же статический метод getCount(), который возвращает значение статической переменной count.

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

Программа генерирует следующий вывод:

N0032

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

 

Рекомендую, так же, посмотреть хорошее видео на эту тему:

Что есть static