Объявление класса вводит новый ссылочный тип. Полный синтаксис объявления класса:
<модификаторы класса> class <имя класса>
<extends-выражение> <implements clause> // заголовок класса
{ // тело класса
<объявления полей>
<объявления методов>
<объявления вложенных классов>
<объявления вложенных интерфейсов>
<объявления конструкторов>
<блоки инициализации>
}
В заголовке класса имени класса предшествует ключевое слово class
. Кроме того, в заголовке класса может быть указана следующая информация:
Тело класса может содержать следующие объявления:
Члены, объявленные как static
, принадлежат классу и называются статическими членами, нестатические члены принадлежат объектам класса и называются членами экземпляра .Также в теле класса могут быть объявления:
Объявления членов, конструкторов и блоков инициализации могут присутствовать в теле класса в произвольном порядке.
Чтобы понять, какой код допустим в объявлениях в классе, давайте рассмотрим различия между статическим и не статическим контекстом. Статический контекст задают статические методы, статические инициализаторы полей, статические блоки инициализации. Не статический контекст задается методами экземпляра, конструкторами, не статическими инициализаторами полей и блоками инициализации экземпляра. Под статическим кодом понимаются выражения и предложения статического контекста, и, подобным образом, под не статическим понимаются выражения и предложения не статического контекста. Одно ключевое различие между двумя контекстами в том, что статический код не может ссылаться на не статические члены.
Полный синтаксис объявления метода:
<модификаторы метода> <возвращаемый тип> <имя метода> (<список формальных параметров>)
<выражение throws> // прототип метода
{ // тело метода
<Объявления локальны переменных>
<Объявления вложенных локальных классов>
<операторы>
}
Прототип метода помимо имени метода может также определять:
void
, если метод не возвращает никакого значения;
throws
.
Список формальных параметров — это разделяемый запятой список параметров для передачи данных в метод во время его вызова. Пустой список параметров должен быть задан как ()
. Каждый параметр представляет собой простое объявление переменной, состоящее из типа и имени.
<модификатор параметра> <тип> <имя параметра>
Сигнатура метода состоит только из имени метода и списка формальных параметров.
Тело метода представляет собой блок, содержащий локальные объявления и операторы метода.
Как и переменные-члены, методы-члены можно охарактеризовать как:
Предложения (statements) в Java можно объединить в разные категории. Так, объявления переменных с явной их инициализацией называются предложениями объявлений (declaration statements). Другие основные категории предложений — предложения управления потоком команд и предложения-выражения.
Предложение-выражение — это выражение, завершающееся точкой с запятой. Вычисление выражения происходит ради его побочных эффектов и его значение отбрасывается. Только некоторые типы выражений выступают в роли предложений. К ним относятся:
new
Одинокая точка с запятой указывает на пустое предложение, которое ничего не делает.
Блок {}
является составным оператором, который используется для объединения нуля или более локальных объявлений и предложений. Блоки могут быть вложенными, так как блок является предложением, которое может содержать другие операторы. Блок может использоваться в любом контексте, где допустимо простое предложение. Составной оператор, заключенный в блок, начинается с левой фигурной скобки ({
) и заканчивается соответствующей правой скобкой (}
). Такой блок не следует путать с блоком инициализации массива в предложениях объявлений.
this
Методы экземпляра принадлежат каждому объекту класса и могут быть вызваны только для объектов. Все члены класса, как статические, так и нестатические, доступны из контекста метода экземпляра. Причина в том, что между всеми методами экземпляра передается неявная ссылка на текущий объект, т.е. на объект, для которого вызывается метод. Сослаться на текущий объект можно в теле метода экземпляра при помощи ключевого слова this
. В теле метода ссылка this
может использоваться как любая другая ссылка на объект для доступа к членам этого объекта. Фактически ключевое слово this
может использоваться в любом нестатическом контексте. Ссылка this
может быть использована как обычная ссылка для доступа к текущему объекту, но ее нельзя изменить.
Ссылка this
на текущий объект употребляется в ситуациях, когда локальные переменные скрыты или имеют одно и то же имя с полем. В примере 4.4 два параметра noOfWatts
и indicator
в конструкторе класса Light
имеют такие же имена, как и поля в классе. В примере также объявлена локальная переменная location
, которая тоже имеет совпадающее имя с одним из полей. Ссылка this
может использоваться для различения полей и локальных переменных. В строке (1) ссылка this
используется для обозначения поля noOfWatts
, которому присваивается значение параметра noOfWatts
. Без ссылки this
в строке (2) значение параметра indicator
присваивается ему же самому, а не полю с одноименным названием, что приведет в результате к логической ошибке. Также и в строке (3), без ссылки this
значение параметра site
присваивается локальной переменной location
, а не одноименному полю.
Пример 4.4. Использование ссылки this
class Light {
// поля
int noOfWatts; // мощность в ваттах
boolean indicator; // включено или выключено
String location; // размещение
// конструктор
public Light(int noOfWatts, boolean indicator, String site) {
String location;
this.noOfWatts = noOfWatts; // (1) присваивание полю.
indicator = indicator; // (2) присваивание параметру.
location = site; // (3) присваивание локальной переменной.
this.superfluous(); // (4)
superfluous(); // эквивалентно вызову в строке (4)
}
public void superfluous() {
System.out.println(this);
} // (5)
public static void main(String[] args) {
Light light = new Light(100, true, "loft");
System.out.println("No. of watts: " + light.noOfWatts);
System.out.println("Indicator: " + light.indicator);
System.out.println("Location: " + light.location);
}
}
Вывод программы:
Light@df6ccd
Light@df6ccd
No. of watts: 100
Indicator: false
Location: null
Если член member
не перекрывается локальными объявлениями, то простое имя member
читается кратким обозначением для this.member
. В особенности ссылка this
может использоваться явно для вызова других методов в классе. Это показано в строке (4) в примере 4.4, где вызывается метод superfluous()
.
Если по каким-либо причинам методу требуется передать ссылку на текущий объект в другой метод, он может это сделать, используя ссылку this
. Это показано в строке (5) в примере 4.4, в которой текущий объект передается в метод println()
.
Обратите внимание, что ссылка this
не может использоваться в статическом контексте, так как статический код не выполняется в контексте какого-либо объекта.
Каждый метод имеет сигнатуру, которая состоит из имени метода, типов и порядка следования параметров в списке формальных параметров. Реализации нескольких методов могут иметь одинаковые имена, однако сигнатуры должны различаться. Это называется перегрузкой метода. Так как перегруженные методы имеют одинаковые имена, их списки формальных параметров должны различаться.
Перегрузку метода можно использовать вместо изобретения новых имен методов, когда требуется несколько реализаций логически одной и той же операции. Программный интерфейс (API) Java 2 SDK интенсивно использует перегрузку методов. Например, класс java.lang.Math
содержит перегруженный метод min()
, который возвращает минимальное значение из двух значений.
public static double min(double a, double b)
public static float min(float a, float b)
public static int min(int a, int b)
public static long min(long a, long b)
В следующем примере показаны пять реализаций метода methodA
.
void methodA(int a, double b) { /* ... */ } // (1)
int methodA(int a) { return a; } // (2)
int methodA() { return 1; } // (3)
long methodA(double a, int b) { return b; } // (4)
long methodA(int x, double y) { return x; } // (5) не верно.
Ниже показаны соответствующие сигнатуры методов.
methodA(int, double) // 1'
methodA(int) // 2': набор параметров.
methodA() // 3': набор параметров.
methodA(double, int) // 4': порядок параметров.
methodA(int, double) // 5': как 1'.
Первые четыре реализации метода methodA
перегружены правильно: каждый раз с различным списком параметров, поэтому сигнатуры отличаются.
Объявление в строке (5) имеет сигнатуру methodA(int, double)
, как в объявлении в строке (1), и поэтому такая перегрузка метода недопустима.
void bake(Cake k) { /* ... */ } // (1)
void bake(Pizza p) { /* ... */ } // (2)
int halfIt(int a) { return a/2; } // (3)
double halfIt(int a) { return a/2.0; } // (4) не верно
Метод bake
корректно перегружен в строках (1) и (2), получены две различные сигнатуры. В реализациях, где отличается только возвращаемый тип (как показано в строках (3) и (4)), такого изменения недостаточно для перегрузки метода, и это вызовет ошибку на этапе компиляции. В определениях должны различаться списки формальных параметров. Перегруженные методы следует рассматривать как отдельные методы, которые случайно имеют одинаковое имя. Методы с одинаковым именем допустимы, так как методы идентифицируются своей сигнатурой. На этапе компиляции выбор правильной реализации основывается на сигнатуре вызова метода. Перегружать можно только методы, объявленные в одном и том же классе или унаследованные классом. Перегрузку (overloading) метода не следует путать с переопределением (overriding) метода.
Многомерные массивы | Конструкторы |