Материал предоставлен https://it.rfei.ru

Классы и методы

Определение классов

Объявление класса вводит новый ссылочный тип. Полный синтаксис объявления класса:

<модификаторы класса> 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) метода.

Многомерные массивыКонструкторы