Объектная модель в Java

advertisement
Объектная модель в Java
Часть 1. Объекты. Инкапсуляция,
наследование, полиморфизм
Понятие объекта
Объект - это мыслимая или реальная сущность, обладающая
характерным поведением, отличительными характеристиками и
являющаяся важной в предметной области (Гради Буч).
 Введение объектов преследует две цели:
• понимание прикладной задачи (проблемы);
• введение основы для реализации на компьютере.
 Каждый объект имеет состояние, обладает некоторым хорошо
определенным поведением и уникальной идентичностью.

Кафедра ЮНЕСКО по НИТ
Свойства объекта

Состояние (state) - совокупный результат поведения объекта, одно
из стабильных условий, в которых объект может существовать. В
любой конкретный момент времени состояние объекта включает в
себя перечень свойств объекта и текущие значения этих свойств.

Поведение (behavior) - действия и реакции объекта, выраженные в
терминах передачи сообщений и изменения состояния; видимая
извне и воспроизводимая активность объекта.

Уникальность (identity) - природа объекта; то, что отличает его от
других объектов.
Кафедра ЮНЕСКО по НИТ
Класс и объект
Объявление класса

модификатор class class_name [extends parent_class]{//тело класса
тип имя_поля; //свойства класса class_name
модификатор class_name(аргументы){тело конструктора}; // конструкторы
//класса class_name
модификатор тип method_name (аргументы){тело метода}; // методы
}
В чем разница между классом и объектом?
 Чтобы работать с объектами, их нужно
сначала создать и задать их исходное
состояние!

Кафедра ЮНЕСКО по НИТ
Создание объекта
Для создания новых экземпляров
класса используются конструкторы
– специальные методы,
предназначенные для создания и
инициализации экземпляра класса.
 Имя конструктора всегда совпадает с
именем класса.
 Чтобы создать объект, конструктор
нужно объединить с операцией new.

Кафедра ЮНЕСКО по НИТ
Пример объявления класса и
конструктора
public class Employee{
private String name;
private double salary;
private Date hiredate;
public Employee(String n, double s, int year, int month, int day){
name=n;
salary=s;
hiredate=(new GregorianCalendar(year,month-1,day)).getTime();
}
}
…
Employee e=new Employee(“James Bond”, 100000, 1950,1,1);
Кафедра ЮНЕСКО по НИТ
Наследование

Наследование (inheritance) - это отношение между классами, при
котором класс использует структуру или поведение другого
(одиночное наследование) или других (множественное
наследование) классов. Наследование вводит иерархию
"общее/частное", в которой подкласс наследует от одного или
нескольких более общих суперклассов. Подклассы обычно
дополняют или переопределяют унаследованную структуру и
поведение.
class Manager extends Employee {
дополнительные поля и методы
}
Ключевое слово extends означает, что создается новый класс.
Существующий класс называется родителем (суперкласс), а
новый класс – дочерним (потомок, подкласс).
Кафедра ЮНЕСКО по НИТ
Наследование. Пример

Задан класс Employee (сотрудник организации), обладающий
свойствами “имя”, ”зарплата”, ”дата приема”. Расширить данный
класс классом Manager с дополнительным полем bonus.
class Manager extends Employee{
private double bonus;
class Employee {
private String name;
private double salary;
private Date hiredate;
public Manager (String n, double s,
int year, int month, int day){
super(n, s, year, month, day); }
}
public String getName{
return name}
public double getSalary{
return salary}
public Date getDate{
return hiredate}
}
Кафедра ЮНЕСКО по НИТ
Наследование. Пример
Каждый экземпляр класса Manager имеет 4 поля – name, salary,
hiredate, bonus.
 Определяя подкласс, нужно указать лишь отличия между
подклассом и суперклассом. Разрабатывая классы, следует
помещать методы общего назначения в суперкласс, а более
специальные – в подкласс.
 Не все методы родительского класса подходят для класса Manager.
В частности, метод getSalary() должен возвращать сумму базовой
зарплаты и премии. Следовательно, нужно реализовать новый
метод, замещающий (overriding) метод класса родителя.

class Manager extends Employee{
….
public void getSalary() {….}
….
}
Кафедра ЮНЕСКО по НИТ
Наследование. Пример
public void getSalary(){
return salary+bonus; // не работает
}
//т.к. поле salary private
public void getSalary(){
double basesalary=getSalary();
return basesalary+bonus; // не работает
}
public void getSalary(){
double basesalary=super.getSalary();
return basesalary+bonus;
}
Кафедра ЮНЕСКО по НИТ
Инкапсуляция
Инкапсуляция (encapsulation) - это сокрытие реализации класса и
отделение его внутреннего представления от внешнего
(интерфейса).
 При использовании объектно-ориентированного подхода не принято
использовать прямой доступ к свойствам какого-либо класса из
методов других классов. Для доступа к свойствам класса принято
использовать специальные методы этого класса для получения и
изменения его свойств.
 Открытые члены класса составляют внешний интерфейс объекта.
Эта та функциональность, которая доступна другим классам.
Закрытыми обычно объявляются все свойства класса, а так же
вспомогательные методы, которые являются деталями реализации
и от которых не должны зависеть другие части системы.
 Благодаря сокрытию реализации за внешним интерфейсом класса
можно менять внутреннюю логику отдельного класса, не меняя код
остальных компонентов системы.

Кафедра ЮНЕСКО по НИТ
Полиморфизм
Полиморфизм (polymorphism) - положение теории типов, согласно
которому имена (например, переменных) могут обозначать объекты
разных (но имеющих общего родителя) классов. Следовательно,
любой объект, обозначаемый полиморфным именем, может посвоему реагировать на некий общий набор операций.
 Слово полиморфизм греческого происхождения и означает
"имеющий много форм".
 Пример. Предположим мы хотим написать векторный графический
редактор, в котором опишем в виде классов набор графических
примитивов - Point, Line, Circle, Box, и т.д. У каждого из этих классов
определим метод draw() для отображения соответствующего
примитива на экране.

Кафедра ЮНЕСКО по НИТ
Полиморфизм
Point[] p = new Point[1000];
Line[] l = new Line[1000];
Circle[] c = new Circle[1000];
Box[] b = new Box[1000];
for (int i = 0; i < p.length;i++){
if(p[i]!=null) p.draw();}
for (int i = 0; i < l.length;i++){
if(l[i]!=null) l.draw();}
for (int i = 0; i < c.length;i++){
if(c[i]!=null) c.draw();}
for (int i = 0; i < b.length;i++){
if(b[i]!=null) b.draw();}
Point p[] = new Point[1000];
p[0] = new Circle();
p[1] = new Point();
p[2] = new Box();
p[3] = new Line();
…
for(int i = 0; i < p.length;i++){
if(p[i]!=null) p.draw();
}
Кафедра ЮНЕСКО по НИТ
Полиморфизм. Поля
При наследовании часто возникают ситуации с одноименными полями и
методами. Необходимо понимать, как одноименные поля и методы будут
сосуществовать.
class parent { int a = 2 ;}
class child extends parent { int a = 3 ;}
---------child c = new child();
Println( c.a);
parent p = c;
Print (p.a);
-------------------------------------------------3
2
Компилятор может опираться только
на тип ссылки. Обе ссылки указывают
на один и тот же объект, но имеют
разные типы.
Поле в наследнике скрыло родительское поле. Но к нему можно обратиться через
super.a
или
((Parent)this).a
Кафедра ЮНЕСКО по НИТ
Полиморфизм. Поля
class parent { int x = 0 ;
public void printX(){ print(x);}
}
class child extends parent { int x = -1 ;
}
Каков результат след. cтрок?
---------new child().printX();
--------------------------------------------------
Метод вызывается с помощью
ссылки типа child, но вызывается
метод, определенный в классе
parent.
Результат: 0
Кафедра ЮНЕСКО по НИТ
Полиморфизм. Поля
Для статических полей конфликтов, связанных с полиморфизмом,
не существует. Пример:
class parent { static int a = 2 ;}
class child extends parent {
static int a = 3 ;}
---------child c = new child();
Println( c.a);
parent p = c;
Print (p.a);
-------------------------------------------------3
2
Нужно вспомнить, как компилятор
обрабатывает обращения
к статическим полям через
ссылочные значения. Все определяется типом ссылки!
Пример слева эквивалентен след.
System.out.println (child.a);
System.out.println (parent.a)
Кафедра ЮНЕСКО по НИТ
Полиморфизм. Методы
class parent {;
public int getVal(){ return 0 ;}
}
class child extends parent {
public int getVal(){ return 1 ;}
}
---------child c = new child();
Println( c.getVal());
parent p = c;
Print (p.getVal());
Результат: 1.
Родительский метод полностью
перекрыт. В этом ключевая
особенность полиморфизма –
потомки могут полностью изменять
родительское поведение, даже если
обращение ведется по ссылке
родительского типа.
Но к родительскому методу можно
обратиться через наследника с
помощью super.
Результат: 1.
Кафедра ЮНЕСКО по НИТ
Полиморфизм. Методы
class parent {;
public int getVal(){ return 0 ;}
public void print(){
System.out.println(getVal());
}
}
class child extends parent {
public int getVal(){ return 1 ;}
}
---------parent p = new child();
p.println();
-----------------------------------------------Res: 1
С помощью ссылки parent вызывается
метод print() из класса родителя. Компилятор не может определить метод
какого класса нужно вызывать, но JVM
на основе объекта, на который
указывает ссылка, определяет метод.
Кафедра ЮНЕСКО по НИТ
Статические элементы
class Human{
private String name;
}
class Human{
public static int total;
}
Прежде, чем обратиться к полю
name, необходимо получить ссылку
на экземпляр класса Human
(невозможно узнать имя вообще,
т.к. оно принадлежит конкретному
человеку). Это поле принадлежит
объекту.
Human h = new Human();
h.name=“MyName”;
Ключевое слово static объявляет
“поле класса” (а не поле конкретного
объекта). Данное поле не
является характеристикой какогото конкретного объекта, оно
относится ко всему классу. Данное
поле существует тогда, когда не
создано ни одного экземпляра
класса.
Кафедра ЮНЕСКО по НИТ
Статические элементы
Для обращения к такому полю ссылка не требуется, достаточно имени
класса.
Human.total++;
Для удобства разрешено обращаться к статическим полям и через ссылки
Но данное обращение конвертируется
компилятором к виду, указанному выше.
Human h = new Human();
h.total++;
Пример
Human h1 = new Human(),
h2 = new Human();
Humqn();
Human.total=5;
Human.total=5;
h1.total++;
h1.total++;
System.out.println(h2.total);
System.out.println(h2.total);
-----------------------------------Res: 6.
Независимо от того, сколько объектов
данного класса существует, поле total
существует в единственном экземпляре.
Кафедра ЮНЕСКО по НИТ
Статические элементы
Аналогично объявляются статические методы
class Human{
private static int total;
public static int getTotal(){
return total;}
}
Для вызова статического метода ссылки на объект не требуется
Human.getTotal();
Хотя для удобства обращения через ссылку разрешены, но принимается
во внимание только тип ссылки
Кафедра ЮНЕСКО по НИТ
Статические элементы
Кроме полей и методов, статическими могут быть инициализаторы. Они
называются инициализаторами класса. Их код выполняется один раз во
время загрузки класса в память JVM.
class Test{
static int b=Test.a;
static int a;
static{
a=5;
}
}
Для инициализации статических полей можно пользоваться только статическими методами и нельзя обращаться к динамическим, т.к. в динамическом контексте всегда есть объект.
Кафедра ЮНЕСКО по НИТ
Ключевое слово this
Если выполнение кода происходит в динамическом контексте, то всегда
есть объект, ассоциированный с ним. В этом случае this возвращает ссылку
на данный объект. Внутри методов this возвращает ссылку на объект, у
которого этот метод вызван.
class Test{
public Object getTest(){
return this;}
public static void main (String[] name){
Test t=new Test();
System.out.println(t.getTest()==t);}
}_________________________________
Res: true
Кафедра ЮНЕСКО по НИТ
Ключевое слово this
Пример “затемняющего” объявления:
class Human{
private String name;
public void setName(String name){
this.name = name;}
}
Пример инициализации полей:
class Test{
//int b=a;нельзя,поле не объявлено
int b = this.a;
int a=5;}
----------------------Res: a=5, b=0
В конструкторах для явного вызова другого конструктора этого же класса
class Test{
int A;
public Test(int j){ A=j; } //первый конструктор
public Test(int j; int k){ //второй конструктор
this(j*k);
//вызываем первый конструктор
print(“Hello, world”);}
}
Кафедра ЮНЕСКО по НИТ
Ключевое слово this

1.
2.
3.
4.
Применение this:
Внутри метода при получении ссылки на самого себя
При затемняющем “объявлении”
При объявлении полей, которые объявляются позже
В конструкторах для явного вызова другого конструктора
этого же класса
Кафедра ЮНЕСКО по НИТ
Ключевое слово super

1.
2.
Применение super:
В первой строке конструктора класса для вызова конструктора классапредка (рассматривали ранее)
Для использования родительских методов, которые были
переопределены в классах потомках
class Parent{
public int getVal(){ return 3;} }
class Child extends Parent{
public int getVal(){ return 5;} }
public static void main(String[] r){
Child c=new Child();
System.out.println(c.getval());
}_________________________
Res: 5
class Child extends Parent{
public int getVal(){
return super.getVal()+1;} }
public static void main(String[] r){
Child c=new Child();
System.out.println(c.getval());
}_________________________
Res: 4
Кафедра ЮНЕСКО по НИТ
Рекомендации по проектированию
классов
Всегда храните данные в переменных,
объявленных как private
 Всегда инициализируйте данные
 Не используйте в классе слишком много простых
типов
 Не для всех полей надо создавать методы доступа
и модификации
 Используйте стандартную форму определения
класса
 Разбивайте на части слишком большие классы
 Выбирайте для классов и методов осмысленные
имена

Кафедра ЮНЕСКО по НИТ
Преобразование типов данных

тождественное (identity)

расширение примитивного типа (widening primitive)

сужение примитивного типа (narrowing primitive)

расширение объектного типа (widening reference)

сужение объектного типа (narrowing reference)

преобразование к строке (String)

запрещенные преобразования (forbidden)
Кафедра ЮНЕСКО по НИТ
Преобразование примитивных
типов
Расширение – переход от менее емкого типа данных к более
емкому (безопасное преобразование).
byte => short => int => long => float => double
char => int => long => float => double (т.к. char - беззнаковый).
Например, char c; int i=50; c = (char)i;
 Сужение – переход от более емкого типа к менее емкому ( риск
потерять данные).
byte => char; short => byte
=> char; char => byte
=> short; int
=> byte
=> short => char; long => int => byte=> short => char =>
int; float => byte=> short => char => int => long; double => byte=> short
=> char => int => long => float.


Сужение дробного типа к целочисленному проходит в два этапа –
сначала перевод к целому типу (long или int), а затем сужение
целого типа.
Кафедра ЮНЕСКО по НИТ
Преобразование ссылочных типов

Расширение – переход от более конкретного типа к менее
конкретному, т.е. от детей к родителям (всегда возможно).
class Parent {int x; ...}
------------------------------------------------class child extends Parent {int y; …}
------------------------------------------------class child2 extends Parent {int z; …}
------------------------------------------------Parent p = new child(); // через p доступно лишь поле x, однако с
// самим объектом child ничего не произошло, просто поле y не видно
// через данную ссылку p
Parent p2 = new child2();
Parent p3 = null; // преобразование от null к любому объектному типу
Кафедра ЮНЕСКО по НИТ
Преобразование ссылочных типов

Сужение – переход по дереву наследования вниз (может
оказаться невозможным).
Parent p = new child();
child c = (child) p; // преобразование успешно
Parent p2 = new child2();
child c2 = (child) p2; // ошибка, т.к. p2 указывает на объект с полями x и z,
а поля x – нет.

Проверка возможности перехода
Parent p = new child();
if (p instanceof child){
child c = (child) p; // преобразование успешно
}
Кафедра ЮНЕСКО по НИТ
Тип переменной и тип ее
значения



Переменная характеризуется трем параметрами: тип, имя,
значение.
Т.к. примитивные переменные хранят само значение, то тип
переменной всегда совпадает с типом значения.
Значение любой переменной ссылочного типа – ссылка на
объект определенного класса или null. Ссылочная
переменная типа A может указывать на объекты,
порожденные от A или его наследников.
Parent p0 = new Parent();
Parent p = new child();
p.New_child_method(); // ошибка, если метод есть только в потомке
((child)p.New_child_method()); // нет ошибки, т.к. тип приведен
Кафедра ЮНЕСКО по НИТ
Download