Скрытие переменных представителей




ИЗУЧЕНИЕ ОСНОВ ОБЪЕКТНО-ОРИЕНТИРОВАННОГО ПРОГРАММИРОВАНИЯ НА ЯЗЫКЕ JAVA

 

Цель работы

 

Изучение основ объектно-ориентированного программирования, создания классов, объектов, на языке Java. Создание и отладка программ. Получение практических навыков алгоритмизации задач на основе объектно-ориентированной парадигмы языка Java.

 

Организация самостоятельной работы студентов

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

Теоретический материал

Базовым элементом объектно-ориентирован­ного программирования в языке Java являет­ся класс. Напомним, что классы в Java не обязательно должны содержать метод main. Единственное назначение этого метода — указать интерпретатору Java, откуда надо начинать выполнение программы. Для того, чтобы создать класс, достаточно иметь исходный файл, в котором будет присутствовать ключевое слово class, и вслед за ним — допустимый идентификатор и пара фигурных скобок для его тела.

class Point {

}

ЗАМЕЧАНИЕ

Имя исходного файла Java должно соответствовать имени хранящегося в нем класса. Регистр букв важен и в имени класса, и в имени файла.

Класс — это шаблон для создания объекта. Класс определяет структуру объекта и его методы, образующие функциональный интерфейс. В процессе выполнения Java-программы система использует определения классов для создания представителей классов. Представители являются реальными объектами. Термины «представитель», «экземпляр» и «объект» взаимозаменяемы. Ниже приведена общая форма определения класса.

class имя_класса extends имя_суперкласса { type переменная1_объекта:

type переменная2_объекта:

type переменнаяN_объекта:

type имяметода1(список_параметров) { тело метода;

}

type имяметода2(список_параметров) { тело метода;

}

type имя методаМ(список_параметров) { тело метода;

}

}

Ключевое слово extends указывает на то, что «имя_класса» — это подкласс класса «имя_суперкласса». Во главе классовой иерархии Java стоит единственный ее встроенный класс — Object. Если вы хотите создать подкласс непосредственно этого класса, ключевое слово extends и следующее за ним имя суперкласса можно опустить — транслятор включит их в ваше определение автома­тически. Примером может служить класс Point, приведенный ранее.

Переменные представителей (instance variables)

Данные инкапсулируются в класс путем объявления переменных между открывающей и закрывающей фигурными скобками, выделяющи­ми в определении класса его тело. Эти переменные объявляются точно так же, как объявлялись локальные переменные в предыдущих примерах. Единст­венное отличие состоит в том, что их надо объявлять вне методов, в том числе вне метода main. Ниже приведен фрагмент кода, в котором объявлен класс Point с двумя переменными типа int.

class Point { int х, у;

}

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

Оператор new

Оператор new создает экземпляр указанного класса и возвращает ссылку на вновь созданный объект. Ниже приведен пример создания и присваивание переменной р экземпляра класса Point.

Point р = new Point();

Вы можете создать несколько ссылок на один и тот же объект. Приведенная ниже программа создает два раз­личных объекта класса Point и в каждый из них заносит свои собст­венные значения. Оператор точка используется для доступа к переменным и методам объекта.

class TwoPoints {

public static void main(String args[]) {

Point p1 = new Point();

Point p2 = new Point();

p1.x = 10;

p1.y = 20;

р2.х = 42;

р2.у = 99;

System.out.println("x = " + p1.x + " у = " + p1.y);

System.out.println("x = " + р2.х + " у = " + р2.у);

} }

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

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

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

тип имя_метода (список формальных параметров) {

тело метода:

}

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

class Point { int х, у;

void init(int a, int b) {

х = а;

У = b;

} }

Вызов метода

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

Скрытие переменных представителей

В языке Java не допускается использование в одной или во вложен­ных областях видимости двух локальных переменных с одинаковыми именами. При этом не запрещается объявлять формальные параметры методов, чьи имена совпадают с именами переменных представителей. Рассмотрим в качестве примера иную версию метода init, в которой формальным пара­метрам даны имена х и у, а для доступа к одноименным переменным текущего объекта используется ссылка this.

class Point { int х, у;

void init(int х, int у) {

this.x = х;

this.у = у } }

class TwoPointsInit {

public static void main(String args[]) {

Point p1 = new Point();

Point p2 = new Point();

p1.init(10,20);

p2.init(42,99);

System.out.println("x = " + p1.x + " у = •• + p-l.y);

System.out.printlnC'x = " + p2.x + " у = •• + p2.y);

} }

Конструкторы

Инициализировать все переменные класса всякий раз, когда создается его очередной представитель — довольно утомительное дело даже в том случае, когда в классе имеются функции, подобные методу init. Для этого в Java предусмотрены специальные методы, называемые конструкторами. Конструктор — это метод класса, который инициали­зирует новый объект после его создания. Имя конструктора всегда со­впадает с именем класса, в котором он расположен (также, как и в C++). У конструкторов нет типа возвращаемого результата - никакого, даже void. Заменим метод init из предыду­щего примера конструктором.

class Point { int х, у;

Point(int х, int у) {

this.x = х;

this.у = у;

} }

class PointCreate {

public static void main(String args[]) {

Point p = new Point(10,20);

System.out.println("x = " + p.x + " у = " + p.у);

} }

Программисты на Pascal (Delphi) для обозначения конструктора используют ключевое слово constructor.

Совмещение методов

Язык Java позволяет создавать несколько методов с одинаковыми именами, но с разными списками параметров. Такая техника называется совмещением методов (method overloading). В качестве примера при­ведена версия класса Point, в которой совмещение методов использовано для определения альтернативного конструктора, который инициализиру­ет координаты х и у значениями по умолчанию (-1).

class Point { int х, у;

Point(int х, int у) {

this.x = х;

this.у = у;

}

Point() {

х = -1;

у = -1;

} }

class PointCreateAlt {

public static void main(String args[]) {

Point p = new Point();

System.out.println("x = " + p.x + " у = " + p.y);

} }

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

ЗАМЕЧАНИЕ

Решение о том, какой конструктор нужно вызвать в том или ином случае, принимается в соответствии с количеством и типом параметров, указанных в операторе new. Недопустимо объявлять в классе методы с одинаковыми именами и сигнатурами. В сигнатуре метода не учитываются имена формальных параметров учитываются лишь их типы и количество.

This в конструкторах

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

class Point { int х, у;

Point(int х, int у) {

this.x = х;

this.у = у;

}

Point() {

this(-1, -1);

} }

В этом примере второй конструктор для завершения инициализации объекта обращается к первому конструктору.

Методы, использующие совмещение имен, не обязательно должны быть конструкторами. В следующем примере в класс Point добавлены два метода distance. Функция distance возвращает расстояние между двумя точками. Одному из совмещенных методов в качестве параметров передаются координаты точки х и у, другому же эта информация пере­дается в виде параметра-объекта Point.

class Point { int х, у;

Point(int х, int у) {

this.x = х;

this. y = y;

}

double distance(int х, int у) {

int dx = this.x - х;

int dy = this.у - у;

return Math.sqrt(dx*dx + dy*dy);

}

double distance(Point p) {

return distance(p.x, p.y);

} }

class PointDist {

public static void main(String args[]) {

Point p1 = new Point(0, 0);

Point p2 = new Point(30, 40);

System.out.println("p1 = " + pi.x + ", " + p1.y);

System.out.println("p2 = " + p2.x + ", " + p2.y);

System.out.println("p1.distance(p2) = " + p1.distance(p2));

System.out.println("p1.distance(60, 80) = " + p1.distance(60, 80));

} }

Обратите внимание на то как во второй фороме метода distance для получения результата вызывается его первая форма.

Наследование

Вторым фундаментальным свойством объектно-ориентированного под­хода является наследование (первый – инкапсуляция). Классы-потомки имеют возможность не только создавать свои собственные переменные и методы, но и наследовать переменные и методы классов-предков. Классы-потомки принято называть подклассами. Непосредственного предка данного класса называют его суперклассом. В очередном примере показано, как расширить класс Point таким образом, чтобы включить в него третью координату z.

class Point3D extends Point { int z;

Point3D(int x, int y, int z) {

this.x = x;

this.у = у;

this.z = z; }

Point3D() {

this(-1,-1,-1);

} }

В этом примере ключевое слово extends используется для того, чтобы сообщить транслятору о намерении создать подкласс класса Point. Как видите, в этом классе не понадобилось объявлять переменные х и у, по­скольку Point3D унаследовал их от своего суперкласса Point.

Super

В примере с классом Point3D частично повторялся код, уже имев­шийся в суперклассе. Вспомните, как во втором конструк­торе мы использовали this для вызова первого конструктора того же класса. Аналогичным образом ключевое слово super позволяет обратить­ся непосредственно к конструктору суперкласса (в С++ для этого используется ключевое слово inherited).

class Point3D extends Point { int z;

Point3D(int x, int у, int z) {

super(x, y); // Здесь мы вызываем конструктор суперкласса this.z=z;

public static void main(String args[]) {

Point3D p = new Point3D(10, 20, 30);

System.out.println(" x = " + p.x + " y = " + p.y +

" z = " + p.z);

} }

Вот результат работы этой программы:

Замещение методов

Новый подкласс Point3D класса Point наследует реализацию метода distance своего суперкласса (пример PointDist.java). Проблема заключается в том, что в классе Point уже определена версия метода distance(mt х, int у), которая возвращает обычное расстояние между точ­ками на плоскости. Мы должны заместить (override) это определение метода новым, пригодным для случая трехмерного пространства. В сле­дующем примере проиллюстрировано и совмещение (overloading), и за­мещение (overriding) метода distance.

class Point { int х, у;

Point(int х, int у) {

this.x = х;

this.у = у;

}

double distance(int х, int у) {

int dx = this.x - х;

int dy = this.у - у:

return Math,sqrt(dx*dx + dy*dy);

}

double distance(Point p) {

return distance(p.х, p.y);

}

}

class Point3D extends Point { int z;

Point3D(int х, int y, int z) {

super(x, y);

this.z = z;

(

double distance(int х, int y, int z) {

int dx = this.x - х;

int dy = this.y - y;

int dz = this.z - z;

return Math.sqrt(dx*dx + dy*dy + dz*dz);

}

double distance(Point3D other) {

return distance(other.х, other.y, other.z);

}

double distance(int х, int y) {

double dx = (this.x / z) - х;

double dy = (this.у / z) - y;

return Math.sqrt(dx*dx + dy*dy);

}

}

class Point3DDist {

public static void main(String args[]) {

Point3D p1 = new Point3D(30, 40, 10);

Point3D p2 = new Point3D(0, 0, 0);

Point p = new Point(4, 6);

System.out.println("p1 = " + p1.x + ", " + p1.y + ", " + p1.z);

System.out.println("p2 = " + p2.x + ", " + p2.y + ", " + p2.z);

System.out.println("p = " + p.x + ", " + p.y);

System.out.println("p1.distance(p2) = " + p1.distance(p2));

System.out.println("p1.distance(4, 6) = " + p1.distance(4, 6));

System.out.println("p1.distance(p) = " + p1.distance(p));

} }

Обратите внимание — мы получили ожидаемое расстояние между трехмерными точками и между парой двумерных точек. В примере используется механизм, который называется динамическим назначением методов (dynamic method dispatch).



Поделиться:




Поиск по сайту

©2015-2024 poisk-ru.ru
Все права принадлежать их авторам. Данный сайт не претендует на авторства, а предоставляет бесплатное использование.
Дата создания страницы: 2016-02-16 Нарушение авторских прав и Нарушение персональных данных


Поиск по сайту: