Чтение онлайн

ЖАНРЫ

Программирование на Java

Вязовик Н.А.

Шрифт:

Чтобы показать, что объект не потерял никаких свойств, произведем следующее обращение:

((Child)p).newChildMethod;

Здесь в начале проводится явное сужение к типу Child. Во время исполнения программы JVM проверит, совместим ли тип объекта, на который ссылается переменная p, с типом Child. В нашем случае это именно так. В результате получается ссылка типа Child, поэтому становится допустимым вызов метода newChildMethod, который вызывается у объекта, созданного в предыдущей строке.

Обратим внимание на важный частный случай - переменная типа Object может ссылаться на объекты любого типа.

В дальнейшем, с изучением новых типов (абстрактных классов, интерфейсов,

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

Таблица 4.1. Целочисленные типы данных.

Тип переменной

Допустимые типы ее значения

Примитивный

В точности совпадает с типом переменной

Ссылочный

* null

* совпадающий с типом переменной

* классы-наследники от типа переменной

Object

* null

* любой ссылочный

Заключение

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

Были рассмотрены все виды приведения типов в Java, то есть переход от одного типа к другому. Они разбиваются на 7 групп, начиная с тождественного и заканчивая запрещенными. Основные 4 вида определяются сужающими или расширяющими переходами между простыми или ссылочными типами. Важно помнить, что при явном сужении числовых типов старшие биты просто отбрасываются, что порой приводит к неожиданному результату. Что касается преобразования ссылочных значений, то здесь действует правило - преобразование никогда не порождает новых и не изменяет существующих объектов. Меняется лишь способ работы с ними.

Особенным в Java является преобразование к строке.

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

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

8. Лекция: Объектная модель в Java

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

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

До этого момента под полями объекта мы всегда понимали значения, которые имеют смысл только в контексте некоторого экземпляра класса. Например:

class Human {

private String name;

}

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

принадлежит какому-то конкретному человеку.

Но бывают данные и иного характера. Предположим, необходимо хранить количество всех людей (экземпляров класса Human, существующих в системе). Понятно, что общее число людей не является характеристикой какого-то одного человека, оно относится ко всему типу в целом. Отсюда появляется название "поле класса", в отличие от "поля объекта". Объявляются такие поля с помощью модификатора static:

class Human {

public static int totalCount;

}

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

Human.totalCount++;

// рождение еще одного человека

Для удобства разрешено обращаться к статическим полям и через ссылки:

Human h = new Human;

h.totalCount=100;

Однако такое обращение конвертируется компилятором. Он использует тип ссылки, в данном случае переменная h объявлена как Human, поэтому последняя строка будет неявно преобразована в:

Human.totalCount=100;

В этом можно убедиться на следующем примере:

Human h = null;

h.totalCount+=10;

Значение ссылки равно null, но это не имеет значения в силу описанной конвертации. Данный код успешно скомпилируется и корректно исполнится. Таким образом, в следующем примере

Human h1 = new Human,

h2 = new Human;

Human.totalCount=5;

h1.totalCount++;

System.out.println(h2.totalCount);

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

Аналогично объявляются статические методы.

class Human {

private static int totalCount;

public static int getTotalCount {

return totalCount;

}

}

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

Human.getTotalCount;

Хотя для удобства обращения через ссылку разрешены, но принимается во внимание только тип ссылки:

Human h=null;

h.getTotalCount;

// два эквивалентных

Human.getTotalCount;

// обращения к одному

// и тому же методу

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

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

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

class Human {

static {

System.out.println("Class loaded");

}

}

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

Поделиться с друзьями: