русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Объявление методов


Дата добавления: 2015-06-12; просмотров: 1079; Нарушение авторских прав


Объявление метода состоит из заголовка и тела метода. Заголовок состоит из:

• модификаторов (доступа в том числе);

• типа возвращаемого значения или ключевого слова void;

• имени метода;

• списка аргументов в круглых скобках (аргументов может не быть);

• специального throws-выражения.

Заголовок начинается с перечисления модификаторов. Для методов доступен любой из трех возможных модификаторов доступа. Также допу­скается использование доступа по умолчанию.

Кроме того, существует модификатор final, который говорит о том, что такой метод нельзя переопределять в наследниках. Можно считать, что все методы final-класса, а также все private-методы любого класса, яв­ляются final.

Также поддерживается модификатор native. Метод, объявленный с таким модификатором, не имеет реализации на Java. Он должен быть на­писан на другом языке (C/C++, Fortran и т.д.) и добавлен в систему в ви­де загружаемой динамической библиотеки (например, DLL для Windows). Существует специальная спецификация JNI (Java Native Interface), опи­сывающая правила создания и использования native-методов.

Такая возможность для Java необходима, поскольку многие компа­нии имеют обширные программные библиотеки, написанные на более старых языках. Их было бы очень трудоемко и неэффективно переписы­вать на Java, поэтому необходима возможность подключать их в таком ви­де, в каком они есть. Безусловно, при этом Java-приложения теряют целый ряд своих преимуществ, таких, как переносимость, безопасность и другие. Поэтому применять JNI следует только в случае крайней необходимости.

Эта спецификация накладывает требования на имена процедур во внешних библиотеках (она составляет их из имени пакета, класса и само­го native-метода), а поскольку библиотеки менять, как правило, очень неудобно, часто пишут специальные библиотеки-'обертки", к которым обращаются Java-классы через JN1, а они сами обращаются к целевым модулям.



Наконец, существует еще один специальный модификатор synchro­nized, который будет рассмотрен в лекции, описывающей потоки выполнения.

После перечисления модификаторов указывается имя (простое или составное) типа возвращаемого значения; это может быть как примитив­ный, так и объектный тип. Если метод не возвращает никакого значения, указывается ключевое слово void.

Затем определяется имя метода. Указанный идентификатор при объ­явлении становится простым именем метода составное имя формирует­ся из имени класса или имени переменной объектного типа и простого имени метода. Областью видимости метода является все объявление тела класса.

Аргументы метода перечисляются через запятую. Для каждого ука­зывается сначала тип, затем имя параметра. В отличие от объявления пе­ременной здесь запрещается указывать два имени для одного типа:

// void calc (double х, у); - ошибка! void calc (double х, double у);

Если аргументы отсутствуют, указываются пустые круглые скобки. Одноименные параметры запрещены. Создание локальных переменных в методе, с именами, совпадающими с именами параметров, запрещено. Для каждого аргумента можно ввести ключевое слово final перед указани­ем его типа. В этом случае такой параметр не может менять своего значе­ния в теле метода (то есть участвовать в операции присвоения в качестве левого операнда).

public void process(int х, final double у) {

x=x*x+Math.sqrt(x);

//y=Math.sin(x); - так писать нельзя, т.к. у - final! }

О том, как происходит изменение значений аргументов, метода, рас­сказано в конце этой лекции.

Важным понятием является сигнатура (signature) метода. Сигнатура определяется именем метода и его аргументами (количеством, типом, по­рядком следования). Если для полей запрещается совпадение имен, то для методов в классе запрещено создание двух методов с одинаковыми сигнатурами.

Например,

class Point { voidgetOU voidget(intx) {} void get(int x, double y) {} void get(double x, int y) {}

Такой класс объявлен корректно. Следующие пары методов в одном классе друг с другом несовместимы:

voidget(){} intgetOO

void get(intx) {} void get(inty) {}

public intgetO {} private intget() {}

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

// пример вызовет ошибку компиляции class Test {intget(){return 5;}

Point get() {return new Point{3,5);}

void print(intx) {System.out.println("it's int! "+x);}

void print(Point p) {System.out.println("it's Point! "+p,x+", "+p.y);}

public static void main (String s[]) {Testt = newTestO; t.print(t.get()); // Двусмысленность!} }

В классе определена запрещенная пара методов get() с одинаковыми сигнатурами и различными возвращаемыми значениями. Обратимся выделенной строке в методе main, где возникает конфликтная ситуация, с которой компилятор не может справиться. Определены два метода printO (у них разные аргументы, а значит, и сигнатуры, то есть это допус­тимые методы), и чтобы разобраться, какой из них будет вызван, нужно знать точный тип возвращаемого значения метода get(), что невозможно.

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

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

Аналогично, третья пара различается лишь модификаторами доступа, что также недопустимо. Наконец, завершает заголовок метода throws-выражение. Оно при­меняется для корректной работы с ошибками в Java и будет подробно рас­смотрено в соответствующей лекции. Пример объявления метода:

public final Java.awt.Point createPositivePoint(int x, int y)

throws lllegalArgumentException {return (x>0 && y>0) ? new Point(x, y): null; }

Далее, после заголовка метода следует тело метода. Оно может быть пустым и тогда записывается одним символом "точка с запятой". Native-методы всегда имеют только пустое тело, поскольку настоящая реализа­ция написана на другом языке.

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

public void emptyO {}

Если в заголовке метода указан тип возвращаемого значения, а не

J^'d, то в теле метода обязательно должно встречаться return-выражение.

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

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

public class Parent { private int x, y;

public ParentO {x=y=0; }

public Parent(int newx, int newy) {x=newx;

y=newy; } }

public class Child extends Parent { public Child(){super{); }

public Child(int newx, int newy) {super(newx, newy); } }

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

Проследим мысленно весь алгоритм создания объекта. Он начина­ется при исполнении выражения с ключевым словом new, за которым следует имя класса, от которого будет порождаться объект, и набор аргу­ментов для его конструктора. По этому набору определяется, какой именно конструктор будет использован, и происходит его вызов. Первая строка его тела содержит вызов родительского конструктора. В свою оче­редь, первая строка тела конструктора родителя будет содержать вызов к его родителю, и так далее. Восхождение по дереву наследования закан­чивается, очевидно, на классе Object, у которого есть единственный конструктор без параметров. Его тело пустое (записывается парой пус­тых фигурных скобок), однако можно считать, что именно в этот момент JVM порождает объект и далее начинается процесс его инициализации. Выполнение начинает обратный путь вниз по дереву наследования. У са­мого верхнего родителя, прямого наследника от Object, происходит про­должение исполнения конструктора со второй строки. Когда он будет полностью выполнен, необходимо перейти к следующему родителю, на один уровень наследования вниз, и завершить выполнение его конструк­тора, и так далее. Наконец, можно будет вернуться к конструктору ис­ходного класса, который был вызван с помощью new, и также продол­жить его выполнение со второй строки. По его завершении объект счи­тается полностью созданным, исполнение выражения new будет закон­чено, а в качестве результата будет возвращена ссылка на порожденный объект.

Проиллюстрируем этот алгоритм следующим примером:

public class GraphicElement {private Int x, y; // положение на экране

public GraphicElement{int nx, int ny) {super(); // обращение к конструктору родителя Object System.out.printlnC'GraphicElement");

x=nx;

y=nx; } }

public class Square extends GraphicElement { private int side;

public Square(int x, int y, int nside) { super{x, y);

System.out.println("Square"); side=nslde; } }

public class SmallColorSquare extends Square { private Color color;

public SmallColorSquare(int x, int y, Color c) {super(x, y, 5);

System.out.println("SmallColorSquare");

color=c; } }

После выполнения выражения создания объекта на экране появится следующее:



<== предыдущая лекция | следующая лекция ==>
Объявление полей | SmallColorSquare


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.354 сек.