- Classes
- Классы, объекты, методы
- Определение класса
- Создание объекта
- Инициализаторы
- Методы класса
- Модификаторы метода — public, protected, private
- Абстрактный класс, abstract class
- Переопределение метода, Override
- Перегрузка методов, overload
- Java рекурсия
- Суперкласс Object
- Проверка принадлежности класса instanceof
- Импорт класса import
Classes
The introduction to object-oriented concepts in the lesson titled Object-oriented Programming Concepts used a bicycle class as an example, with racing bikes, mountain bikes, and tandem bikes as subclasses. Here is sample code for a possible implementation of a Bicycle class, to give you an overview of a class declaration. Subsequent sections of this lesson will back up and explain class declarations step by step. For the moment, don’t concern yourself with the details.
public class Bicycle < // the Bicycle class has // three fields public int cadence; public int gear; public int speed; // the Bicycle class has // one constructor public Bicycle(int startCadence, int startSpeed, int startGear) < gear = startGear; cadence = startCadence; speed = startSpeed; >// the Bicycle class has // four methods public void setCadence(int newValue) < cadence = newValue; >public void setGear(int newValue) < gear = newValue; >public void applyBrake(int decrement) < speed -= decrement; >public void speedUp(int increment) < speed += increment; >>
A class declaration for a MountainBike class that is a subclass of Bicycle might look like this:
public class MountainBike extends Bicycle < // the MountainBike subclass has // one field public int seatHeight; // the MountainBike subclass has // one constructor public MountainBike(int startHeight, int startCadence, int startSpeed, int startGear) < super(startCadence, startSpeed, startGear); seatHeight = startHeight; >// the MountainBike subclass has // one method public void setHeight(int newValue) < seatHeight = newValue; >>
MountainBike inherits all the fields and methods of Bicycle and adds the field seatHeight and a method to set it (mountain bikes have seats that can be moved up and down as the terrain demands).
Классы, объекты, методы
Java является объектно-ориентированным языком, поэтому такие понятия как «класс» и «объект» играют в нем ключевую роль. Любую программу на Java можно представить как набор взаимодействующих между собой объектов.
Шаблоном или описанием объекта является класс (class), а объект представляет экземпляр класса. Можно провести следующую аналогию. У нас у всех есть некоторое представление о машине — наличие двигателя, шасси, кузова и т.д. Есть некоторый шаблон auto — этот шаблон можно назвать классом. Реально же существующий автомобиль auto_solaris (фактически экземпляр данного класса) является объектом этого класса.
Определение класса
Класс определяется с помощью ключевого слова сlass. Вся функциональность класса представлена его членами — полями (полями называются переменные класса) и методами. Например, класс Book мог бы иметь следующее описание :
Таким образом, в классе Book определены три переменных и один метод Info, который выводит значения этих переменных.
Кроме обычных методов в классах используются также и специальные методы, которые называются конструкторами. Конструкторы нужны для создания нового объекта данного класса и, как правило, выполняют начальную инициализацию объекта. Название конструктора должно совпадать с названием класса :
class Book < public String name; public String author; public int year; Book()< this.name = "неизвестно"; this.author = "неизвестно"; this.year = 0; >Book(String name, String author, int year) < this.name = name; this.author = author; this.year = year; >public void Info()
Класс Book имеет два конструктора. Первый конструктор без параметров присваивает «неопределенные» начальные значения полям. Второй конструктор присваивает полям класса значения, которые передаются через его параметры.
Так как имена параметров и имена полей класса в данном случае у нас совпадают — name, author, year, то мы используем ключевое слово this. Это ключевое слово представляет ссылку на текущий объект. Поэтому в выражении this.name = name; первая часть this.name означает, что name — это поле текущего класса, а не название параметра name. Если бы у нас параметры и поля назывались по-разному, то использовать слово this было бы необязательно.
Мы можем определить несколько конструкторов для установки разного количества параметров и затем вызывать один конструктор класса из другого :
public class Book < public String name; public String author; public int year; Book(String name, String author) < this.name = name; this.author = author; >Book(String name, String author, int year) < // вызов конструктора с двумя параметрами this(name, author); // определение третьего параметра this.year = year; >>
Вызов конструктора класса с двумя параметрами производится с помощью ключевого слова this, после которого в скобках указывается список параметров.
Создание объекта
Чтобы непосредственно использовать класс в программе, надо создать его объект. Процесс создания объекта двухступенчатый: вначале объявляется переменная данного класса, а затем с помощью ключевого слова new и конструктора непосредственно создается объект, на который и будет указывать объявленная переменная :
Book b; // объявление переменной определенного типа/класса b = new Book(); // выделение памяти под объект Book
После объявления переменной Book b; эта переменная еще не ссылается ни на какой объект и имеет значение null. Затем создаем непосредственно объект класса Book с помощью одного из конструкторов и ключевого слова new.
Инициализаторы
Кроме конструктора начальную инициализацию полей объекта можно проводить с помощью инициализатора объекта. Так можно заменить конструктор без параметров следующим блоком :
public class Book < public String name; public String author; public int year; /* начало блока инициализатора */ < name = "неизвестно"; author = "неизвестно"; year = 0; >/* конец блока инициализатора */ Book(String name, String author, int year) < this.name = name; this.author = author; this.year = year; >>
Методы класса
Метод класса в объектно-ориентированном программировании — это функция или процедура, принадлежащая какому-либо классу или объекту.
Как и процедура в процедурном программировании, метод состоит из некоторого количества операторов для выполнения определенного действия и может иметь набор входных параметров.
Различают простые методы и статические методы :
- простые методы имеют доступ к данным объекта конкретного экземпляра (данного класса);
- статические методы не имеют доступа к данным объекта, и для их использования не нужно создавать экземпляры (данного класса).
Методы предоставляют интерфейс, при помощи которого осуществляется доступ к данным объекта некоторого класса, тем самым, обеспечивая инкапсуляцию данных.
Кроме имени и тела (кода) у метода есть ряд других характеристик:
Модификаторы метода — public, protected, private
Модификаторы метода определяют уровень доступа. В зависимости от того, какой уровень доступа предоставляет тот или иной метод, выделяют:
- public : открытый — общий интерфейс для всех пользователей данного класса;
- protected : защищённый — внутренний интерфейс для всех наследников данного класса;
- private : закрытый — интерфейс, доступный только изнутри данного класса.
Такое разделение интерфейсов позволяет сохранять неизменным открытый интерфейс, но изменять внутреннюю реализацию.
Для того чтобы создать статический метод, перед его именем надо указать модификатор static. Если этого не сделать, то метод можно будет вызывать только в приложении к конкретному объекту данного класса (будет нестатическим).
Класс может включать метод main, который должен иметь уровень доступа public; к нему обращается виртуальная машина Java, не являющаяся частью какого-либо пакета.
Абстрактный класс, abstract class
Абстрактный класс в объектно-ориентированном программировании — базовый класс, который не предполагает создания экземпляров. Абстрактные классы реализуют на практике один из принципов ООП — полиморфизм. Абстрактный класс может содержать (и не содержать) абстрактные методы. Абстрактный метод не реализуется для класса, в котором описан, однако должен быть реализован для его неабстрактных потомков. Пример абстрактного класса, включающего две абстрактные функции.
public abstract class Price < public abstract int getPriceCode(); public abstract double summPrice(int days); public int bonusPrice(int days) < return 1; >>
Переопределение метода, Override
В реализации ReleasePrice, наследующего свойства класса Price, «реализуем» абстрактные методы и «переопределяем» метод с использованием аннотации @Override :
public class ReleasePrice extends Price < public int getPriceCode() < return Disk.NEW_RELEASE; >public double summPrice(int days) < double summ = days*3; return summ; >/* * Метод bonusPrice переопределяем. В родительском метод возвращал 1, а здесь уже идет расчет */ @Override public int bonusPrice(int days) < if (days >1) return 2; return 1; > >
Теперь, если в родительском класса Price метод bonusPrice будет удален или переименован, то среда разработки должна выдать соответствующее сообщение. Компилятор также выдаст сообщение об ошибке.
Перегрузка методов, overload
Совокупность имени метода и набора формальных параметров называется сигнатурой метода. Java позволяет создавать несколько методов с одинаковыми именами, но разными сигнатурами. Создание метода с тем же именем, но с другим набором параметров называется перегрузкой. Какой из перегруженных методов должен выполняться при вызове, Java определяет на основе фактических параметров, передаваемых методу.
Пример класса Test с тремя перегруженными методами test :
public class Test < void test() < System.out.println("параметр отсутствует"); >void test(int a) < System.out.println("a = " + String.valueOf(a)); >void test (int a, int b) < System.out.println("a + b = " + String.valueOf(a + b)); >void test(double d) < System.out.println("d = " + String.valueOf(d)); >>
Пример использования класса Test:
Java рекурсия
Рекурсией называется метод (функция), которая внутри своего тела вызывает сама себя.
Рассмотрим пример рекурсивного метода вычисления факториала. Для того чтобы вычислить n!, достаточно знать и перемножить между собой (n-1)! и n. Создадим метод, реализующий описанный способ.
static int fact (int n) < if (n == 1) < return 1; >else if (n == 2) < return 2; >else < return fact(n-1) * n; >>
Указанный рекурсивный метод вычисляет факториал натурального числа.
Рассмотрим пример, вычисляющий через рекурсию n-ое число Фибоначчи. Напомним, как выглядят первые элементы этого ряда: 1 1 2 3 5 8 13 …
static int fib (int n) < if (index else if (n == 1) return 1; else if (n == 2)) return 1; return fib (n-2) + fib (n-1); >
Суперкласс Object
В Java есть специальный суперкласс Object и все классы являются его подклассами. Поэтому ссылочная переменная класса Object может ссылаться на объект любого другого класса. Так как массивы являются тоже классами, то переменная класса Object может ссылаться и на любой массив.
У класса Object есть несколько важных методов:
Метод | Описание |
---|---|
Object clone() | Функция создания нового объекта, не отличающий от клонируемого |
boolean equals(Object object) | Функция определения равенства текущего объекта другому |
void finalize() | Процедура завершения работы объекта; вызывается перед удалением неиспользуемого объекта |
Class getClass() | Функция определения класса объекта во время выполнения |
int hashCode() | Функция получения хэш-кода объекта |
void notify() | Процедура возобновления выполнения потока, который ожидает вызывающего объекта |
void notifyAll() | Процедура возобновления выполнения всех потоков, которые ожидают вызывающего объекта |
String toString() | Функция возвращает строку описания объекта |
void wait() | Ожидание другого потока выполнения |
void wait(long ms) | Ожидание другого потока выполнения |
void wait(long ms, int nano) | Ожидание другого потока выполнения |
Методы getClass(), notify(), notifyAll(), wait() являются «финальными» (final) и их нельзя переопределять.
Проверка принадлежности класса instanceof
Для проверки принадлежности класса какому-либо объекту необходимо использовать ключевого слова instanceof. Иногда требуется проверить, к какому классу принадлежит объект. Это можно сделать при помощи ключевого слова instanceof. Это логический оператор, и выражение foo instanceof Foo истинно, если объект foo принадлежит классу Foo или его наследнику, или реализует интерфейс Foo (или, в общем виде, наследует класс, который реализует интерфейс, который наследует Foo).
Пример с рыбками. Допустим имеется родительский класс Fish и у него есть унаследованные подклассы SaltwaterFish и FreshwaterFish. Необходимо протестировать, относится ли заданный объект к классу или подклассу по имени
SaltwaterFish nemo = new SaltwaterFish(); if(nemo instanceof Fish) < // рыбка Немо относится к классу Fish // это может быть класс Fish (родительский класс) или подкласс типа // SaltwaterFish или FreshwaterFish. if(nemo instanceof SaltwaterFish) < // Немо - это морская рыбка! >>
Данная проверка удобна во многих случаях. Иногда приходится проверять принадлежность класса при помощи instanceof, чтобы можно было бы разделить логику кода:
void checkforTextView(View v) < if(v instanceof TextView) < // Код для элемента TextView >else < // Для других элементов View >>
Импорт класса import
Оператор import сообщает компилятору Java, где найти классы, на которые ссылается код. Любой сложный объект использует другие объекты для выполнения тех или иных функций, и оператор импорта позволяет сообщить о них компилятору Java. Оператор импорта обычно выглядит так:
import packane_name.Class_Name_To_Import;
За ключевым словом следуют класс, который нужно импортировать. Имя класса должно быть полным, то есть включать свой пакет. Чтобы импортировать все классы из пакета, после имени пакета можно поместить ‘.*;’
IDE Eclipse упрощает импорт. При написании кода в редакторе Eclipse можно ввести имя класса, а затем нажать Ctrl+Shift+O. Eclipse определяет, какие классы нужно импортировать, и добавляет их автоматически. Если Eclipse находит два класса с одним и тем же именем, он выводит диалоговое окно с запросом, какой именно класс вы хотите добавить.
Статический импорт
Существует ещё статический импорт, применяемый для импорта статических членов класса или интерфейса. Например, есть статические методы Math.pow(), Math.sqrt(). Для вычислений сложных формул с использованием математических методов, код становится перегружен. К примеру, вычислим гипотенузу.
hypot = Math.sqrt(Math.pow(side1, 2) + Math.pow(side2, 2));
В данном случае без указания класса не обойтись, так как методы статические. Чтобы не набирать имена классов, их можно импортировать следующим образом:
import static java.lang.Math.sqrt; import static java.lang.Math.pow; . hypot = sqrt(pow(side1, 2) + pow(side2, 2));
После импорта уже нет необходимости указывать имя класса.
Второй допустимый вариант, позволяющий сделать видимыми все статические методы класса:
import static java.lang.Math.*;
В этом случае не нужно импортировать отдельные методы. Но данный подход в Android не рекомендуется, так как требует больше памяти.