Лекция 3. ООП в Java (часть 1) © 2013 NetCracker Technology Corporation Confidential План лекции • Основные понятия ООП • Объявление классов • Создание объектов • Работа с пакетами • Некоторые полезные классы © 2013 NetCracker Technology Corporation Confidential 2 Основные понятия ООП Принципы ООП Другие важные понятия • 0. Абстрагирование • Классы • 1. Инкапсуляция • Объекты • 2. Наследование • Поля • 3. Полиморфизм • Методы • Пакеты • Область видимости • Интерфейсы © 2013 NetCracker Technology Corporation Confidential 3 Абстрагирование • Абстрагирование — это способ выделить набор значимых характеристик объекта, исключая из рассмотрения незначимые. public class MyClock { public int hours; public int minutes; public void nextMinute() { minutes++; if (minutes >=60) { minutes=0; hours++; if (hours >=24) { hours=0; } } } } © 2013 NetCracker Technology Corporation Confidential 4 Инкапсуляция • Инкапсуляция — объединение данных и методов работающих с ними; обеспечение публичного интерфейса, скрытие реализации ‒ данные и вспомогательные методы «скрывают» с помощью сужения области видимости ‒ предоставляют публичный интерфейс • Это позволяет: ‒ в будущем менять реализацию без изменения интерфейса ‒ обеспечить «защиту от дурака» © 2013 NetCracker Technology Corporation Confidential 5 Инкапсуляция — пример public class MyClock { public int hours; public int minutes; public class MyClock { private int hours; private int minutes; // ... public int getHours() { return hours; } } public int getMinutes() { return minutes; } // ... } © 2013 NetCracker Technology Corporation Confidential 6 Наследование • Наследование — описание нового класса на основе уже существующего с частично или полностью заимствующейся функциональностью • В отличие от С++ в Java наследование единичное (но есть интерфейсы) ‒ у любого класса есть только один непосредственный предок ‒ граф наследования представляет собой дерево ‒ все объекты прямо или косвенно унаследованы от класса Object • С помощью наследования реализуется отношение IS-A (объект является чем-то). Не путать с HAS-A (объект содержит что-то) ‒ любой человек является приматом (человек extends примат) ‒ не всякий примат является человеком ‒ человек является животным, рыба является животным, человек не является рыбой • Проверить является ли объект реализацией какого-либо класса или интерфейса можно с помощью оператора instanceof ‒ иванов instanceof Человек == true ‒ иванов instanceof Примат == true ‒ иванов instanceof Рыба == false © 2013 NetCracker Technology Corporation Confidential 7 Наследование — пример public class MyPreciseClock extends MyClock { private int seconds; public int getSeconds() { return seconds; } public void nextSecond() { seconds++; if (seconds>=60) { seconds = 0; nextMinute(); } } } ... MyClock mc = new MyClock(); MyPreciseClock mpc = new MyPreciseClock(); System.out.println(mc instanceof MyClock); System.out.println(mc instanceof MyPreciseClock); System.out.println(mpc instanceof MyClock); System.out.println(mpc instanceof MyPreciseClock); © 2013 NetCracker Technology Corporation Confidential Результат: // true true // false false // true true // true true 8 Полиморфизм • Полиморфизм — использование объектов с одинаковыми интерфейсами без информации о типе и внутренней структуре объектов • Для этого нужно в наследниках переопределить (override) методы, объявленные в базовом классе или интерфейсе ‒ в отличие от С++/С#, в Java все методы являются виртуальными, специально это указывать не надо • Выбор нужного метода выполняется автоматически во время выполнения программы (runtime) на основании информации о типе объекта ‒ полиморфизм работает только для методов! ‒ никогда не пытайтесь переопределять поля!! ‒ выбор поля осуществляется на этапе компиляции на основании типа ссылки на объект, а не типа самого объекта!!! • Начиная с Java 1.5 рекомендуется переопределяемые методы помечать аннотацией @Override © 2013 NetCracker Technology Corporation Confidential 9 Полиморфизм — пример 1 public class MyClock { // ... public String toString() { return "MyClock [" + hours + ":" + minutes + "]"; } } public class MyPreciseClock extends MyClock { // ... public String toString() { return "MyPreciseClock [" + getHours() + ":" + getMinutes() + ":" + seconds + "]"; } } ... MyClock mc = new MyClock(); MyPreciseClock mpc = new MyPreciseClock(); MyClock mpc2 = new MyPreciseClock(); System.out.println(mc.toString()); System.out.println(mpc.toString()); System.out.println(mpc2.toString()); © 2013 NetCracker Technology Corporation Confidential Результат: MyClock [0:0] // MyClock [0:0] MyPreciseClock [0:0:0] // MyPreciseClock [0:0:0] MyPreciseClock [0:0:0] // MyPreciseClock [0:0:0] 10 Полиморфизм — пример 2 class A{ String name = "Class A"; String getName() { return name; } } class B extends A{ String name = "Class B"; // Никогда так не делайте (не переопределяйте поля)! String getName() { return name; } } public class AB{ public static void main(String[] args) { A a = new A(); B b = new B(); A ab= new B(); Результат: System.out.println("a : " + a.name + " " + a.getName()); a : Class A Class A System.out.println("b : " + b.name + " " + b.getName()); b : Class B Class B System.out.println("ab: " + ab.name+ " " + ab.getName()); ab: Class A Class B } } © 2013 NetCracker Technology Corporation Confidential 11 План лекции • Основные понятия ООП • Объявление классов • Создание объектов • Работа с пакетами • Некоторые полезные классы © 2013 NetCracker Technology Corporation Confidential 12 Объявление классов • Объявление класса [<модификаторы>] class <ИмяКласса> [extends <ИмяБазовогоКласса>] [implements <ИмяИнтерфейса1>[, <ИмяИнтерфейса2> [, ...]]] { <объявление полей, конструкторов и методов класса> } • Объявление поля [<модификаторы>] <тип> <имяПоля> [=<значение_по_умолчанию>]; • Объявление метода [<модификаторы>] <тип_возвращаемых_данных> <имяМетода> ([список аргументов]) [throws <список классов исключительных ситуаций>]{ <блок программного кода> } © 2013 NetCracker Technology Corporation Confidential 13 Статические поля и методы • Статические поля и методы принадлежат всему классу, а не конкретным объектам, поэтому: • С ними можно работать без необходимости создания объектов ‒ начинающие ленивые программисты очень любят static поля и методы, т.к. для работы с ними не нужно создавать объекты. НЕ ДЕЛАЙТЕ ТАК! ‒ используйте static там, где это действительно необходимо (см. паттерны) • Статические поля не привязаны к конкретным объектам, поэтому: • из них можно обращаться только к другим static полям и методам • из них нельзя обращаться к нестатическим полям и методам • в них отсутствует this (см. ниже) • Из вне обращаться к static полям и методам можно: • через имя объекта (имя_объекта.статическое_поле) • через имя класса (Имя_класса.статическое_поле) ‒ предпочтительнее через имя класса (выше читаемость кода) • Для static методов не работает полиморфизм ‒ можно «переопределить», но выбор метода выполняется на этапе компиляции © 2013 NetCracker Technology Corporation Confidential 14 Перегрузка методов (method overloading) • Перегрузка методов (method overloading) – определение нескольких методов с одинаковыми названиями, но разными аргументами ‒ не путать с override – переопределение в потомке метода, объявленного в базовом классе • Сигнатура метода – название метода + порядок и тип параметров • Тип возвращаемого значения и декларация исключений не является частью сигнатуры метода в языке Java • Выбор нужного метода выполняется на этапе компиляции по сигнатуре метода • При перегрузке не должно быть 2х методов с одинаковой сигнатурой ‒ если у 2х методов совпадут сигнатуры в одном классе – ошибка компиляции ‒ если у метода в потомке совпадет сигнатура с методом в базовом классе, то получится override, а не overload © 2013 NetCracker Technology Corporation Confidential 15 Конструкторы (1) • Конструктор – специальный «метод», который вызывается при создании объекта для его инициализации • Конструкторы можно перегружать (overload) • Отличия конструкторов от методов: • • • • • имя конструктора совпадает с именем класса (с учетом регистра) отсутствует возвращаемый тип. Совсем. Даже слово void не указывается не может быть вызван после создания объекта не может быть перегружен (overload) или переопределён (override) в потомке не может быть abstract, final, static, ... ‒ допускаются только модификаторы области видимости (public, protected, private) ‒ если конструкторы не видны – невозможно создать экземпляр (пример – класс Math) • Если конструкторы не объявлены, создается конструктор по умолчанию: ‒ область видимости – как у класса ‒ без параметров ‒ ничего не делает кроме вызова конструктора базового класса без параметров; если в базовом классе такового нет – ошибка компиляции © 2013 NetCracker Technology Corporation Confidential 16 Конструкторы (2) • В первой строке конструктора можно: • вызвать другой конструктор данного класса с помощью this(параметры) • вызвать конструктор базового класса с помощью super(параметры) • сделать что-нибудь другое, и тогда компилятор автоматически вставит первой строкой вызов super() без параметров ‒ если в базовом классе такого конструктора нет, то ошибка компиляции • Не рекомендуется вызывать из конструктора нестатические методы данного класса ‒ если в наследнике их переопределить, то могут возникнуть проблемы ‒ статические методы переопределить нельзя, т.е. с ними проблем не будет • Не рекомендуется из конструктора вызывать методы других классов, передавая в них this ‒ объект до конца не проинициализирован, могут возникнуть проблемы • Если конструктор бросит Exception, инициализация прекратится, и частично проинициализированный объект станет доступен сборщику мусора ‒ об этом нужно помнить, если вдруг решите переопределить finalize() (см. ниже) © 2013 NetCracker Technology Corporation Confidential 17 План лекции • Основные понятия ООП • Объявление классов • Создание объектов • Работа с пакетами • Некоторые полезные классы © 2013 NetCracker Technology Corporation Confidential 18 Создание объектов • В Java объекты создаются и хранятся только в куче (heap) ‒ в Java не бывает объектов в стеке или в сегменте данных как с C++ ‒ в Java объекты не передаются по значению как с C++ ‒ в Java объекты не передаются по ссылке как с C++ ‒ в Java объекты вообще никак не передаются (они остаются лежать в куче, где лежали) ‒ в Java передаются ссылки на объекты. Как и примитивы, они передаются по значению • В результате создания объекта мы получаем ссылку на объект ‒ с помощью этой ссылки можно обратиться только к этому объекту ‒ отсутствуют адресная арифметика, произвольный доступ к памяти, преобразование ссылки в примитив и наоборот ‒ копирование ссылки не приводит к созданию копии объекта • Способы создания объектов: ‒ оператор new ‒ метод clone() ‒ serialization ‒ reflection в следующих лекциях © 2013 NetCracker Technology Corporation Confidential 19 Создание объектов – оператор new 1. Если класс не был загружен в память он загружается ‒ инициализируются статические поля, выполняются блоки статической инициализации 2. Выделяется место в памяти под объект 3. Инициализируются нестатические поля и выполняются нестатические блоки инициализации • Поля инициализируются значениями, указанными в описании класса • Если они не были указаны, то поля инициализируются значениями по-умолчанию: ‒ числовые поля = 0, логические поля = false, ссылки = null 4. Вызывается конструктор (см. ниже), использованный в операторе new ‒ если в данном классе в явном виде конструктор не описан, используется конструктор по-умолчанию (см. ниже) • перед выполнением конструктора происходит вызов конструкторов всех суперклассов по цепочке ‒ если явном конструктор не вызывается, неявно вызывается конструктор по-умолчанию 5. Когда конструктор завершился, new возвращает ссылку на новый объект © 2013 NetCracker Technology Corporation Confidential 20 this • this ссылается на текущий объект • Нельзя использовать в статических методах • Можно использовать в нестатических методах и конструкторах для: • получения ссылки на данный объект: ‒ this • доступа к полю, имя которого перекрыто областью видимости параметра или локальной переменной: ‒ this.имяполя • вызова перегруженного конструктора данного класса: ‒ this(параметры) © 2013 NetCracker Technology Corporation Confidential 21 this – пример public class Student { String name; public Student(String name) { this.name = name; } public Student() { this("No Name"); конструктора } // область видимости // вызов перегруженного public void addToGroup(Group group) { group.addStudent(this); // передача ссылки на себя } } © 2013 NetCracker Technology Corporation Confidential 22 super • super используется для вызова конструкторов и методов базового класса • Вызов переопределенного метода базового класса super.имяМетода(параметры) • Вызов конструктора базового класса super(параметры) ‒ вызов конструктора базового класса может быть только в первой строке конструктора ‒ если перед вызовом конструктора суперкласса все-таки требуется выполнить какой-то код, его можно включить в статический метод и сделать так: super(myStaticMethod(параметры)); или this(myStaticMethod(параметры)); © 2013 NetCracker Technology Corporation Confidential 23 super – пример class Employee { String name; public Employee(String name) { this.name = name; } public String toString() { return "Name:" + name; } } class Manager extends Employee { String department; public Manager(String name, String departament) { super(name); // вызов конструктора базового класса this.department = departament; } public String toString() { return super.toString() + " is manager of " + department; // вызов переопределенного метода базового класса } } © 2013 NetCracker Technology Corporation Confidential 24 План лекции • Основные понятия ООП • Объявление классов • Создание объектов • Работа с пакетами • Некоторые полезные классы © 2013 NetCracker Technology Corporation Confidential 25 Пакеты • Пакеты предназначены для организации иерархического пространства имен классов. Цель – избежать конфликта имен классов • Пакеты могут включать в себя классы и другие пакеты • На уровне файловой системы: пакет = каталог, класс = файл • Чтобы избежать конфликта имен пакетов в качестве пакета верхнего уровня используют доменное имя своей компании в обратном порядке: ‒ com.netcracker, ru.edunc, ua.kpi.nc, ... • имяпакета принято записывать маленькими буквами никак не выделяя регистр или составляющие его слова: ‒ mypackage.mycompany.example.com • java-файл должен начинаться с: package packagename; • Если в явном виде пакеты не используются, то классы размещаются в пакете «по-умолчанию». Не делайте так. ОСОБЕННО в JavaEE-приложениях © 2013 NetCracker Technology Corporation Confidential 26 Импортирование классов • Полное имя класса (fully qualified class name) – имяпакета.ИмяКласса • Чтобы использовать короткое имя класса, его нужно импортировать: package mypackage; import java.util.Date; public class MyClass { Date date = new Date(); // Просто Date вместо java.util.Date } • import пишется после package, но перед class • Если нужно несколько классов из одного пакета, можно использовать «*» import java.util.*; • включаются все классы из указанного пакета ‒ классы из пакетов в указанном пакете не включаются • это никак не влияет ни на размер class-файла, ни на быстродействие • import работает на этапе компиляции • если заглянуть в середину class-файла, там записаны полные имена классов • Автоматически импортируются все классы из пакета java.lang.* © 2013 NetCracker Technology Corporation Confidential 27 Статический импорт • Импортируются не сами классы, а их статические методы • Java 1.5 и выше public class Test { public static void main(String[] args) { double x = 0.5; double y = Math.sin(x)*Math.sin(x) + Math.cos(x)*Math.cos(x); System.out.println(y); } } import static java.lang.Math.*; public class Test { public static void main(String[] args) { double x = 0.5; double y = sin(x)*sin(x) + cos(x)*cos(x); System.out.println(y); } } © 2013 NetCracker Technology Corporation Confidential 28 План лекции • Основные понятия ООП • Объявление классов • Создание объектов • Работа с пакетами • Некоторые полезные классы © 2013 NetCracker Technology Corporation Confidential 29 Класс Object • Класс Object – корень дерева иерархии наследования всех классов Доступ public Тип boolean Имя equals(Object obj) public int hashCode() public String toString() protected Object clone() protected void finalize() public Class<?> getClass() public void notify() public void notifyAll() public void wait() public void wait(long timeout) public void wait(long timeout, int nanos) © 2013 NetCracker Technology Corporation Confidential 30 Класс Class • Объекты класса Class содержат информацию о классах, загруженных в виртуальную машину. Обеспечивают информацию о классах во время выполнения программы (Reflection) • Некоторые методы: • • • • • • getName() getSuperclass() forName(String className) newInstance() getFields() getMethods() © 2013 NetCracker Technology Corporation Confidential 31 Классы-обертки • Представляют значение примитивного типа в виде объекта • • • • • • • • Integer Byte Character Short Long Double Float Boolean • Дополнительные полезные функции • преобразование в/из строк • хранение констант (MIN_VALUE, MAX_VALUE, NaN, POSITIVE_INFINITY, ...) • другие функции (в зависимости от типа) • Объекты являются неизменяемыми (immutable) © 2013 NetCracker Technology Corporation Confidential 32 Класс String • Представляет собой строку • Объекты String – immutable! После того как объект создан, его состояние невозможно изменить • Класс String является final. Невозможно создать его наследников • Некоторые полезные методы – их очень много (см. JavaDoc) • Важно помнить: ни один из этих методов не изменяет данный объект (immutable) • «Изменяющие» методы создают новые объекты и возвращают ссылки на них. • String умеет работать с юникодом, локалями, регулярными выражениями • Для объектов String работает оператор «+» (конкатенация) • Если нужно очень интенсивно выполнять операции над строками, лучше использовать StringBuffer или StringBuilder © 2013 NetCracker Technology Corporation Confidential 33 Классы StringBuffer и StringBuilder • StringBuffer и StringBuilder представляют собой mutable строку, с которой очень эффективно выполняются операции добавления, вставки и удаления символов ‒ не создаются новые объекты как при использовании String • StringBuffer • начиная с Java 1.0 • синхронизирован (thread-safe) • работает чуть медленнее чем StringBuilder • StringBuilder • начиная с Java 1.5 • не синхронизирован (non thread-safe) • работает чуть быстрее чем StringBuffer © 2013 NetCracker Technology Corporation Confidential 34 Классы System и Runtime • System – очень полезный класс. Много полезных статических полей и методов • • • • • • • • Поля in, out, err static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) static Console console() static long currentTimeMillis() static long nanoTime() static void exit(int status) static String lineSeparator() методы для работы со свойствами (properties) и переменными окружения (environment variables) • Runtime – тоже полезный класс. Много методов как у класса System, но эти методы – нестатические • для работы с ними вначале нужно получить ссылку на объект с помощью вызова Runtime. getRuntime() © 2013 NetCracker Technology Corporation Confidential 35 Работа с датами/временем • Класс Date (java.util.Date) • Частично устаревший класс (содержит много Deprecated методов) • Корректно работает со временем в формате «количеством миллисекунд, прошедших с January 1, 1970, 00:00:00 GMT» • Для других целей лучше пользоваться классом Calendar • Класс Calendar • Учитывает «хитрые» особенности работы с датой/временем • Много дополнительных функций по сравнению с Date • Совместим с Date ‒ методы getTime(), setTime() • Умеет работать с локалями • Является абстрактным классом (невозможно создать его экземпляр) • Чтобы работать с Calendar нужно вызвать статический метод Calendar. getInstance(). Он вернет ссылку на объект класса унаследованного от Calendar (у нас – GregorianCalendar) © 2013 NetCracker Technology Corporation Confidential 36 Другие полезные классы • Math содержит много статических методов для вычисления математических функций ‒ sin, cos, log, exp, pow, random, .... • Random генератор псевдослучайных величин ‒ более богатые функции, чем у Math.random • Arrays содержит много статических методов для работы с массивами ‒ копирование, поиск, сортировка, заполнение • Pattern, Matcher – работа с регулярными выражениями ‒ см. http://docs.oracle.com/javase/tutorial/essential/regex/index.html • Locale – работа с настройками локализации (язык, национальные настройки) © 2013 NetCracker Technology Corporation Confidential 37 Thank you! © 2013 NetCracker Technology Corporation Confidential 38