Лекции по Java SE Максим Букасов, киевский учебный центр NetCracker
План лекции
Модификаторы доступа и области видимости
Модификаторы доступа и конструкторы
Модификаторы доступа и наследование
final – классы, методы, поля, переменные, параметры
Инициализация final поля
enum – перечислимый тип
constants vs. enum
Абстрактные классы
Абстрактные классы – примеры из Java standard libraries
Интерфейсы
Интерфейсы – синтаксис
Интерфейсы – пример 1
Интерфейсы – пример 2
«Нестандартное» применение интерфейсов
Интерфейсы vs. Абстрактные классы
Вложенные классы (Nested Classes)
Типы вложенных классов
Статические вложенные классы – пример
Внутренние классы – пример
Локальные классы – пример
Анонимные классы – пример
ClassLoader
ClassLoader – архитектура
517.01K
Категория: ПрограммированиеПрограммирование

Лекции по Java SE. Лекция 4. ООП в Java (часть 2)

© 2013 NetCracker Technology Corporation Confdential Лекции по Java SE Максим Букасов, киевский учебный центр NetCracker Лекция 4.

ООП в Java (часть 2)2 © 2013 NetCracker Technology Corporation Confdential План лекции

• Модификаторы доступа и области видимости

• fnal – классы, методы, поля, переменные, параметры

• enum – перечислимый тип

• Абстрактные классы

• Интерфейсы

• Вложенные классы

• ClassLoader3 © 2013 NetCracker Technology Corporation Confdential Модификаторы доступа и области видимости

• 3 модификатора‒ private‒ protected‒ public

• 4 области видимости Область видимости Тот же класс* Тот же пакет Класс- наследник Кто угодно private Да -- - (default) Да -- protected Да- public Да * В т.ч.: классы, вложенные в данный класс;

класс-«хозяин» вложенного класса4 © 2013 NetCracker Technology Corporation Confdential Модификаторы доступа и конструкторы

• Конструктор по умолчанию (deault constructor) имеет такой же модификатор доступа, как и сам класс

• Если спрятать все конструкторы, невозможно извне создать экземпляр класса

• примеры:‒ утилитные классы со статическими методами (Math, System)‒ паттерн Singleton public class Singleton { private static final Singleton INSTANCE =new Singleton();

private Singleton() {} public static Singleton getInstance() { return INSTANCE;

}}5 © 2013 NetCracker Technology Corporation Confdential Модификаторы доступа и наследование

• При переопределении ( override ) метода, область видимости в наследнике:

• можно оставлять такой же

• можно расширять (ослаблять)

• нельзя сужать (ужесточать)

• Причина – класс-наследник расширяет базовый класс, и, соответственно, должен обладать всеми возможностями базового класса ( полиморфизм)

• Пример, как делать нельзя ( не работает!): class Officer { String name;

public String getName() { return this .name;} class SecretAgent extends Officer { private String getName() { return this .name;} class ErrorDemo { public static void errorDemo() { SecretAgent agent =new SecretAgent();

// Полиморфизм: Officer officer = agent;

System.out .println(officer.getName());} private -метод невозможно переопределить6 © 2013 NetCracker Technology Corporation Confdential inal – классы, методы, поля, переменные, параметры

• inal класс – невозможно расширить (создать наследника)

• полезно при создании immutable классов‒ пример: класс String

• inal метод – невозможно переопределить в наследнике•в inal-классе , все методы неявно являются fnal

• private методы неявно являются fnal

• inal поле – после инициализации невозможно изменить значение

• полезно при создании immutable классов

• объявление констант‒ в Java зарезервированное слово const никак не используется‒ константы объявляются с помощью public static fnal‒ начиная с Java 1.5 для констант порядковых шкал лучше использовать enum (см.

ниже)

• inal параметры методов и локальные переменные

• используются для доступа к ним из локальных или анонимных классов (см.

ниже)

• повышение читаемости кода в сложных алгоритмах;

+ человеческий фактор

• компилятор гарантирует отсутствие изменений7 © 2013 NetCracker Technology Corporation Confdential Инициализация inal поля

• Если на уровне класса объявлено fnal поле, то для него:

• нет значений по умолчанию (требуется явная инициализация)

• компилятор гарантирует отсутствие изменений или повторной инициализации

• можно (и нужно!) проинициализировать один (и только один!) раз: static поля non-static поля - либо при объявлении поля - либо в статическом блоке инициализации - либо при объявлении поля - либо в нестатическом блоке инициализации - либо в конструкторах ( помним про this(...)!) class StaticFinalDemo { // Init here final staticint finalStatic = 1;

static { // OR here // finalStatic = 2;

}} class NonStaticFinalDemo { // Init here finalint finalNonStatic = 1;

{ // OR here // finalNonStatic = 2;

} NonStaticFinalDemo() { // OR here // finalNonStatic = 3;

}}8 © 2013 NetCracker Technology Corporation Confdential enum – перечислимый тип

• Недостатки целочисленных констант для номинальных и порядковых шкал:‒ можно по ошибке указать константу из другого класса‒ можно по ошибке вместо константы указать неправильное число

• Начиная с Java 1.5 появился перечислимый тип

• Особенности перечислимых типов:‒ компилятор отслеживает совместимость типов‒ enum может содержать поля, методы‒ enum может реализовывать интерфейсы‒ enum не может расширять классы, т.к.

уже неявно унаследован от java.lang.Enum‒ любой enum содержит стандартный функционал, унаследованный от java.lang.Enum‒ можно использовать с оператором switch-case-deault‒ гарантируется, что будет создано не более одного экземпляра для каждой константы (используется для реализации паттерна Singleton)‒ см.

http:// docs.oracle.com/javase/tutorial/java/javaOO/enum.html9 © 2013 NetCracker Technology Corporation Confdential constants vs.

enum public static final enum class Month { public static finalint JANUARY=1;

public static finalint FEBRUARY=2;

public static finalint MART=3;} public class FinalExample { void setDate(int day,int month) { // ...

} void someMethod() { // Compiled & Ok setDate(23, Month.FEBRUARY);

// Error, but compiled setDate(Month.MART, 8);

}} enum Month { JANUARY, FEBRUARY, MART;} public class EnumExample { void setDate(int day, Month month) { // ...

} void someMethod() { // Compiled & Ok setDate(23, Month.FEBRUARY);

// Error and NOT compiled setDate(Month.MART, 8);

}}10 © 2013 NetCracker Technology Corporation Confdential Абстрактные классы

• Абстрактный класс – «класс-заготовка» на основе которой с помощью наследования позже будут созданы конкретные классы.‒ моделирование отношения IS-A , необходимого для полиморфизма

• При объявлении класса используется модификатор abstract

• Может содержать объявления методов, которые будут определены в наследниках‒ модификатор abstract , вместо тела метода{} просто точка с запятой

• Если в классе есть хоть один абстрактный метод, класс тоже должен быть абстрактным‒ класс может быть абстрактным даже если в нем нет абстрактных методов

• Невозможно создать экземпляр абстрактного класса‒ но можно использовать ссылку данного типа для обращения к объектам-потомкам

• Может иметь конструкторы‒ эти конструкторы можно вызывать из конструкторов потомка, используя super11 © 2013 NetCracker Technology Corporation Confdential Абстрактные классы – примеры из Java standard libraries

• Calendar‒ GregorianCalendar

• InputStream‒ AudioInputStream, ByteArrayInputStream, FileInputStream, FilterInputStream, ObjectInputStream, PipedInputStream, SequenceInputStream, StringBuerInputStream

• OutputStream‒ ByteArrayOutputStream, FileOutputStream, FilterOutputStream, ObjectOutputStream, PipedOutputStream

• ClassLoader‒ SecureClassLoader

• TimerTask‒ HelloTimerTask  (см.

далее)12 © 2013 NetCracker Technology Corporation Confdential Абстрактные классы – пример (слайд 1 из 2) abstract class Person { String name;

public Person(String name) { this .name=name;} abstract public void sayHello();

public void doHandshake(Person p) { // do handshake with p System.out .println( " ----- " + name + " give hand to " + p.name + " -----");} public void greet(Person p) { doHandshake(p);

sayHello();} class RussianPerson extends Person { public RussianPerson(String name) { super (name);} public void sayHello() { System.out .println(" Привет!");} class AmericanPerson extends Person { public AmericanPerson(String name) { super (name);} public void sayHello() { System.out .println(" Hello!");}13 © 2013 NetCracker Technology Corporation Confdential Абстрактные классы – пример (слайд 2) public class Test { public static void main(String[] args) { Person ivan =new RussianPerson(" Иван");

Person john =new AmericanPerson(" John");

ivan.greet(john);

john.greet(ivan);} ----- Иван give hand to John ----- Привет! ----- John give hand to Иван ----- Hello!14 © 2013 NetCracker Technology Corporation Confdential

• В Java нет множественного наследования классов (оговорка: в Java 8 есть частичный аналог – deault implementations)‒ нет множественного наследования – нет проблемы ромба‒ любой класс имеет только одного непосредственного предка‒ чтобы показать, что объект IS-A «что-то» и при этом IS-A «что-то еще», используются интерфейсы

• Интерфейс – абстрактный тип, содержащий объявления методов и констант‒ соглашение о том, какие методы должен иметь класс, реализующий данный интерфейс

• Интерфейс может быть унаследован от другого/других интерфейсов‒ для интерфейсов поддерживается множественное наследование‒ т.к.

интерфейсы содержат только объявления методов (без их реализации) нет проблемы ромба

• Класс может реализовывать любое количество интерфейсов‒ т.к.

интерфейсы содержат только объявления методов (без их реализации) нет проблемы ромба Интерфейсы15 © 2013 NetCracker Technology Corporation Confdential Интерфейсы – синтаксис

• Синтаксис: <modifier> interface <Name> [ extends <interface> [,<interface>]* ] { <member_declaration>*}

• В интерфейсе могут присутствовать:

• объявления методов‒ всегда public abstract , даже если явно это не указано‒ не могут быть private, protected, fnal, static

• константы‒ всегда public static fnal , даже если явно это не указано‒ не могут быть private, protected

• Выбирайте названия методов в интерфейсах с умом.

При реализации они не должны конфликтовать с именами методов из других интерфейсов данного класса‒ в Java нельзя реализовать в одном классе два разных метода с одинаковой сигнатурой из разных интерфейсов (см.

ниже Пример 2)16 © 2013 NetCracker Technology Corporation Confdential Интерфейсы – пример 1 interface Speakable { void speak();

// implicitly public abstract} class Human implements Speakable { public void speak() { // must be public System.out .println("Hello! How are You?");} class Cat implements Speakable { public void speak() { // must be public System.out .println("Meow");} class InterfaceDemo { public static void main(String[] args) { Speakable[] creatures = {new Human(),new Cat(),new Cat()};for (Speakable s:creatures) { s.speak();

}}17 © 2013 NetCracker Technology Corporation Confdential Интерфейсы – пример 2 interface Animal { void eat();

// eat something void sleep();

// sleep somewhere void walk();

// walk voidrun();

// walk very fast} // java.lang:// interface Runnable { // abstract public voidrun ();

// execute code in parallel thread // } class Cat implements Animal, Runnable { public void eat() { // eat whiskas, drink milk } public void sleep() { // sleep in warm place } public void walk() { // walk quietly } public voidrun () { // ????????????????????????? }}18 © 2013 NetCracker Technology Corporation Confdential «Нестандартное» применение интерфейсов

• Антипаттерн «Хранилище констант»‒ http:// en.wikipedia.org/wiki/Constant_interface

• Паттерн «Маркерный интерфейс» interface Constants { doublePI = 3.14159;

double PLANCK_CONSTANT = 6.62606896e-34;} class Calculations implements Constants { public double getReducedPlanckConstant() { return PLANCK_CONSTANT / (2 *PI);

}} java.io.Serializable: public interface Serializable {} import java.io.Serializable;

class MyClass { void myMethod(Object o) { if (o instanceof Serializable) { // do something } }}19 © 2013 NetCracker Technology Corporation Confdential Интерфейсы vs.

Абстрактные классы Возможность Абстрактный класс Интерфейс Множественное наследование/реализац ия-+ Декларация абстрактных методов+ Реализация конкретных методов+ - (до Java 8) Объявление констант+ Объявление полей+- Определение конструкторов+- Создание экземпляров- Область видимости элементов любая public20 © 2013 NetCracker Technology Corporation Confdential Вложенные классы (Nested Classes)

• Вложенный класс – класс, объявленный внутри другого класса

• Удобно применять когда нужно:

• для данного класса создать вспомогательный класс, не видимый другим классам

• создать класс, который будет видеть «внутренности» данного класса, но иметь совершенно другого предка или интерфейс

• Чаще всего применяется для реализации компараторов, листенеров (обработчиков событий) и т.д.

class Outer { // ...} class Nested { // ...}21 © 2013 NetCracker Technology Corporation Confdential Типы вложенных классов

• Статические вложенные классы (static nested classes)‒ между объектами внешнего и вложенного классов неявной связи нет‒ если такая связь нужна – делается «вручную»‒ можно создавать объекты вложенного класса без объектов внешнего и наоборот

• Внутренние классы (inner classes)‒ есть неявная связь между объектом внутреннего класса и объектом класса-хозяина‒ для создания объекта внутреннего класса нужен объект внешнего класса

• Локальные классы‒ внутренний класс, который объявляется внутри метода‒ «видит» локальные переменные и параметры метода

• Анонимные классы‒ локальный класс, который не имеет явного имени22 © 2013 NetCracker Technology Corporation Confdential import java.util.*;

// Outer class public class StaticNestedDemo extends Object { private String helloString = "Hello, world!";

// Static Nested Class static class HelloTimerTask extends TimerTask { private StaticNestedDemo outer;

public HelloTimerTask(StaticNestedDemo outer) { this.

outer = outer;

} @Override public void run() { System.out .println( outer.

helloString);

}} void helloWorld() { TimerTask timerTask =new StaticNestedDemo.HelloTimerTask( this);

Timer timer =new Timer();

timer.schedule(timerTask, 1000, 1000);} public static void main(String[] args) {new StaticNestedDemo().helloWorld();} Статические вложенные классы – пример Т.к.

статические вложенные классы не имеют привязки к «хозяину», ее нужно создать «вручную» Во вложенном классе this относится к объекту вложенного класса, во внешнем – к внешнему23 © 2013 NetCracker Technology Corporation Confdential import java.util.*;

//Outer class public class InnerClassDemo extends Object { private String helloString = "Hello, world!";

// Inner Class class HelloTimerTask extends TimerTask { @Override public void run() { System.out .println( helloString);

} } void helloWorld() { TimerTask timerTask = this.new HelloTimerTask();

//// "this" is optional: // TimerTask timerTask = new HelloTimerTask();

Timer timer =new Timer();

timer.schedule(timerTask, 1000, 1000);

} public static void main(String[] args) {new InnerClassDemo().helloWorld();

}} Внутренние классы – пример Т.к.

внутренние классы имеют неявную ссылку на «хозяина», «вручную» ее создавать не нужно Во вложенном классе this относится к объекту вложенного класса.

Если нужна ссылка на «хозяина»: ИмяВнешнегоКласса.this Для создания вложенного объекта нужен внешний объект Если вложенный объект создается снаружи внешнего класса, то используется синтаксис: внешнийОбъект.new ВнутреннийКласс()24 © 2013 NetCracker Technology Corporation Confdential import java.util.*;

public class LocalClassDemo extends Object { private String helloString = "Hello, %s%s!\n";

void hello( final String who) { final String mr = "Mr.

";

// Local Class (inside of method) class HelloTimerTask extends TimerTask { @Override public void run() { System.out .printf( helloString , mr, who);

} } TimerTask timerTask =new HelloTimerTask();

Timer timer =new Timer();

timer.schedule(timerTask, 1000, 1000);} public static void main(String[] args) {new LocalClassDemo().hello( "World");} Локальные классы – пример Т.к.

внутренние классы имеют неявную ссылку на «хозяина», «вручную» ее создавать не нужно вложенный класс имеет доступ к локальным переменным и параметрам, если они являются fnal25 © 2013 NetCracker Technology Corporation Confdential Анонимные классы можно создавать на базе класса или интерфейса import java.util.*;

public class AnonymousClassDemo { private String helloString = "Hello, %s%s!\n";

void hello( final String who) { final String mr = "Mr.

";

// Anonymous class TimerTask timerTask =new TimerTask() { @Override public void run() { System.out .printf( helloString , mr, who);

} };

Timer timer =new Timer();

timer.schedule(timerTask, 1000, 1000);

} public static void main(String[] args) {new AnonymousClassDemo().hello( "World");

}} Анонимные классы – пример Т.к.

внутренние классы имеют неявную ссылку на «хозяина», «вручную» ее создавать не нужно вложенный класс имеет доступ к локальным переменным и параметрам, если они являются fnal26 © 2013 NetCracker Technology Corporation Confdential ClassLoader

• ClassLoader – механизм динамической загрузки классов в JVM‒ обычно используется ленивая загрузка классов при первом обращении к ним‒ при желании программист может сам агрессивно загрузить нужные ему классы

• Любой класс загружается ClassLoader-ом только один раз

• ClassLoader-ов может быть несколько.

Они организованы в виде дерева‒ это позволяет создавать пространства имен, загружая несколько раз один и тот же класс в одну и ту же JVM‒ так, например, работают сервера приложений

• Программист может создавать свои ClassLoader-ы

• При поиске подходящего ClassLoader-а используется принцип делегации‒ это защищает систему от попыток загрузить системный класс из непроверенных источников

• Выгрузка классов происходит тогда, когда нет живых ссылок ни на класс, ни на его ClassLoader27 © 2013 NetCracker Technology Corporation Confdential ClassLoader – архитектура Bootstrap jre/lib/*.jar Extensions jre/lib/ext/*.jar каталоги из java.ext.dirs System CLASSPATH User ClassLoader A User ClassLoaderA1 User ClassLoaderA2 Bootstrap Extensions System User ClassLoader A User Object loadClass fndClass Thank you!28 © 2013 NetCracker Technology Corporation Confdential
English     Русский Правила