1 / 34

InfB203 Увод в програмирането с Java

InfB203 Увод в програмирането с Java. Стефан Пулов e - mail:s_pulov@abv.bg. Съдържание. Повторно използване на кода ( reusing code) Композиция Наследяване Достъп до наследените компоненти. Инициялизация на наследените компоненти

Download Presentation

InfB203 Увод в програмирането с Java

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. InfB203Увод в програмирането с Java Стефан Пулов e-mail:s_pulov@abv.bg

  2. Съдържание • Повторно използване на кода (reusing code) • Композиция • Наследяване • Достъп до наследените компоненти. • Инициялизация на наследените компоненти • Преобразуване на обекти към производен и към базов клас (downcasting/upcasting). • Предефиниране и припокриване на методи и предефиниране на методи в производен клас (overloading и overriding). • Полиморфизъм • Абстрактни класове • Сравняване на обекти. • Задачи за самостоятелна работа

  3. Повторно използване на кода (reusing code) • Едно от най-големите предимства на обектно ориентираното програмиране е лекотата, с която вече написан код може да бъде изпозван отново и отново. Два са начините това да стане • Композиция • Наследяване

  4. Композиция • Говорим за композиция когато член данна на даден клас е от обектен тип. Типичен примр за исползване на композиция е класа Person, който написхме в някое от предните занятия: class Person { String name; //Използване на композиция … }

  5. Композиция • Както вече знаем достъпа до компонентите на даден клас от методи не принадлежащи на класа става чрез използване на оператора “.”, а от методи на класа директно. Веднъж достъгнали до дадена, член данна от обектен тип, ние имаме достъп до всички методи на класа от, който е въпросната член данна и по този начин използваме вече написания код.

  6. Наследяане • Наследяването е механизъм при, който ние създаваме нови класове на базата на вече съществуващ, казвайки че новосъздадения клас притежава всички свойства на стария плюс някакви допълнителни характеристики. Класа на базата на, който създаваме новия такъв се нарича базов, а новия се нарича производен.

  7. Наследяване • Нека Base e даден клас без значение какви методи и член данни той притежава. Ще дефинираме наследник на Baseнаречен Derive. class Derive extends Base { //Дефиниция на член данните и методите //на Derive }

  8. Достъп до наследените компоненти. • Веднъж създаден един клас като наследник на друг той притежава всички полета и методи на своя базов клас. За разлика обаче от базовия клас производния няма достъп до дефинираните като private компоненти на базовия клас. • Когато изучавахме спецификаторите за достъп казахме, че те са 4 на брой: public, private, protected, (default). Тогава не разгледахме спецификатора за достъп protected понеже казахме, че той има отношение към наследяването, а именно: До компонентите на деден клас дефинирани като protectedимат достъп само методите на същия клас и методите на неговоте наследници. Методите на всички останали класове нямат достъп до тях.

  9. Достъп до наследените компоненти. • Следната таблица описва различните права на достъп до компонентите на базов клас.

  10. Достъп до наследените компоненти. • Да се напише клас Personи негов наследник Student. Базовия клас да има set и get методи и конструктор без аргументи. Да дефинира и метода toString. • Както виждаме от горния пример за обекта от класа студент може да викаме всички пуплични методи. Ако освен това се намираме и в същия пякет може да викаме и всички методи с подразбиращ се спецификатор за достъп.

  11. Инициялизация на наследените компоненти • От горния пример се вижда също, че конструктора на базовия клас човек се извиква автоматично преди изпълнението на тялото на конструктора на класа студент. Какво става, обаче когато базовия клас не притежава конструктор без аргументи или подразбиращ се такъв. Първото което ни идва на ум да направим е да инициализираме директно компонентите на базовия клас. Възникват обаче два основни проблема: • Компонентите може да са недостъпни (дефинирани са privete) • Производния клас не знае какви евентуални ограничения са наложени над тези компоненти

  12. Инициялизация на наследените компоненти • За да се избегнат горните проблеми в Java e реализиран механизам чрез, който конструктор на производен клас може да извика конструктор на базовия си клас. Това ства чрез използване на запазената дума supe. Как точно това ства ще се види от следващия пример.

  13. Инициялизация на наследените компоненти • Да се дефинира клас Student1, който е същия като класа Sudent, но да притежава и конструктор с 5 аргумента инициализиращ както наследените член данни така и собствените си. • Както виждаме от горния пример обращението super(<argumet list>) e първия оператор в тялото на конструктора на производния клас. Това оператор представлява обръщение към конструктор на базовия клас, като това към кой точно става чрез сравняване на броя и типовете на формалните с фактическите параметри.

  14. Преобразуване на обекти към производен и към базов клас (downcasting/upcasting). • Вече видяхме, че производния клас притежава методите и полетата на своя базов клас и напрактика всеки обект от производен клас може да бъде разглеждан като обект от своя базов клас. Поради тази причина в Java е позволено присвояването на обект от производен клас на манипулатор от базовия му клас. • Пример: • Person p; • Student1 s = new Student1("Peter","8501011212",true,5623,6); • p = s;

  15. Преобразуване на обекти към производен и към базов клас (downcasting/upcasting). • Присвояването в горния пример, при което на манипултор от базовия клас присвояваме обект от производен такъв се нарича upcasting.

  16. Преобразуване на обекти към производен и към базов клас (downcasting/upcasting). • Да разгледаме отново програмния фрагмент от преди малко • Person p; • Student1 s = Student1("Peter","8501011212",true,5623,6); • p = s; • По-нататъчната работа с манипулатора p се осъществява все едно той сочи обект от тип Person (можем да извикаме единствено методи на класа Person). Има случаи, в които това не е достатъчно и ние исламе да се възползваме от факта, че действително имаме манипулатор сочещ Student1 па макар и той да е от тип Person. Това става чрес след явно преобразуване на типа Person към Student1 по следния начин: • Person p; • Student1 s = new Student1("Peter","8501011212",true,5623,6); • p = s; • Student1 s1 = (Student1)p;

  17. Преобразуване на обекти към производен и към базов клас (downcasting/upcasting). • Преобразуването на обекта от тип Person към обект от тип Student1 в горния пример се нарича downcasting. • Понятията downcasting и upcasting са произлезли от начина, по който обикновено се рисуват йерархиите от класове (като дървета с корен базовия клас)

  18. Предефиниране и припокриване на методи и предефиниране на методи в производен клас (overloading и overriding). • Има случаи когато логиката на програмата налага създаването на два или повече метода в даден клас с едни и същи иентификатори, но с различни параметри (както знаем методите се различават по своя прототип, който вкючва освен идентификатора не метода, а и неговия списък с аргументи). Това се нарича предефиниране (overloading ).

  19. Предефиниране и припокриване на методи и предефиниране на методи в производен клас (overloading и overriding). • Ще се върнем към класа Rat и ще му добавим функции sum, div, mult, sub, които предифинират вече съществуващите такива и приемат ргументи цели числа и връщат отново рационално число.За да направим реализацията по чиста ще създадем конструктор с един аргумент цяло число.

  20. Предефиниране и припокриване на методи и предефиниране на методи в производен клас (overloading и overriding). • До тук разгледахме какво става, ако две функции в рамките на един клас имат едни и същи имена. А какво ства, ако имаме два класа свързани чрез наследяване и в базовия и производния клас искаме функции с еднакви имена и различни параметри? Говорим ли отново за предефиниране?

  21. Предефиниране и припокриване на методи и предефиниране на методи в производен клас (overloading и overriding). • Отговора на горния въпрос е и да и не понеже всичко зависи от спецификатора за достъп на метода в базовия клас. • Ако метода е достъпен от производния клас то тогава говорим за предифиниране • Ако метода не е достъпен не говорим за предефиниране понеже в производния клас нямаме избот между методи с еднакви имена.

  22. Предефиниране и припокриване на методи и предефиниране на методи в производен клас (overloading и overriding). • А какво става когато в базовия и основния клас имаме методи със съвпадащ прототип? В такъв случай говорим за припокриване (overriding). С припокриване сме се сблъсквали вече в нашата работа макар и неосъзнато. Както вече не веднъж е ствало дума Java е език в който класовете образуват единна йерархия с корен Object. До сега това не значеше много за нас, но след като знаем наследяване можем да кажем, че всеки клас е наследник на Object (макар и не директен). Когато създаваме клас без да дефинираме негов базов клас ние неявно дефинираме Object като базов такъв.

  23. Предефиниране и припокриване на методи и предефиниране на методи в производен клас (overloading и overriding). • Да се върнем сега на припокриването. В класа Object е дефиниран метода public String toString(), който ние не веднъж вече припокрихме в класовете, които дефинирахме.

  24. Предефиниране и припокриване на методи и предефиниране на методи в производен клас (overloading и overriding). • Да се модифицира класа Student1 като се припокрии метода toString на клас Person. • Нещо интересно , което виждаме в метода toString на класа Student2 е обръщението super.toString(). Това е обръението към метода на базовия клас, който ние сме припокрили. • От изпълнението на Example5 виждаме, че за класа Student1 се изпълнява метода toString на базовия му клас Person, а за класа Student2 неговия метод, който припокрива този в Person.

  25. Полиморфизъм • Полиморфизма е средтво на обектно ориентираните езици позволяващо на един и същ код (обръщение към метод) да има различен ефект в зависимост от типа на реалния обект, за който извикваме метода. Ще илюстрираме с пример какво се има в предвид.

  26. Полиморфизъм • Да се напише следната йерархия от класове: Базов клас Figure2D с функция calSurfaceвръщаща 0. Производен клас Triangle зададен с три страни (реални числа). Производен клас Quadrat задаен с дължината на страната си (реално число). И двата производни класа да приполриват функцията calSurfaceтака, че да връща големината на лицето на сответната функция.

  27. Полиморфизъм • Както може да се види от изхода на Example6 при последните три извиквания на метода calcSurface през манипулатор от тип calcSurface бяха извикани методите на класовете от които са реалните обекти към, които сочи манипулатора. Именно в това се сътои полиморфизма: определянето на действието, което ще се извърши (метода, който ще се изпълни) става в зависимост от типа на реалния обект към, който сочи даден манипулатор, а не от типа от който е манипулатора. Механизма, който позволява това да се случи се нарича късно или динамично сързваме (определяне на метода, който ще се изпълне по време на изпълнение на програмата). Трябва да се отбележи, чеза обръщението към всички методи в Java се използва този тип свързвне.

  28. Абстрактни класове • В примера, който разгледахме класа Figure2D притежаваше метод calcSurface, който винаги втъщаше 0 неговата единствена задача е да бъде там за да можем да извикаме полиморфно през манипулатор от този клас същия метод в някой от неговите наследници. • Би било много удобно, ако дефинираме клас, от който изрично сме казали, че няма да създаваме обекти. И на който един или повече методи нямат тяло. Такива класове се наричат абстрактни и в Java се създават с поставяне на запазената дума abstract пред дефиницията на класа. Допълнително ако искаме да дефинираме метод без тяло (отново се нарича абстрактен) то отново поставяме abstract пред неговата дефниция.

  29. Абстрактни класове • Да се направи класа Figure2D абстрактен, както и неговия единствен метод. • Както виждаме от примера компилтора съобщава за грешка при опит за създаване на обект от абстрактен клас. От друга страна няма никакъв поблем да създадем манипулатор от такъв тип и да му присвояваме посредством upCasting обекти от някой от производните класове.

  30. Сравняване на обекти. • След като вече знаем какво е наследяване, припокриване на методи, upcast и downcast сме готови да се занимаем със сравняването на два обекта. Нека да рзгледаме следния програмен фрагмент. Rat r1 = new Rat(1,2); Rat r2 = new Rat(1,2); System.out.println(r1 == r2); r1 = r2; System.out.println(r1 == r2); • Резултата от изпълнението на горния код ще доведе до това, че на екрана ще се изпишат последователно false и true. Причината за това е, че при сравняването с оператора == се сравняват стойностите на манипулаторите, а не на обектите към, които те сочат. • Ако искаме да сравняваме обектите към, които манипулаторите сочат трябва да напишем някакъв метод, който да върши това защото Java няма по какво да определи, че два обекта са равни.

  31. Сравняване на обекти. • Създадтелите на Java са знаели, че сравняването на два обекта е операция без, която никоя програма не би била пълноценна. Затова те са дефинирали метода equals в клас Object, кайто както знаем е родител на всички останали класове и следователно метода equals е наследен във всички класове независимо дали ние сме ги написали или са дошли с библиотеките на Java.

  32. Сравняване на обекти. • Имплементацията на този метод в класа Object реализира сравнението ==. Следни програмен код би има същия резултат като горния. r1 = new Rat(1,2); r2 = new Rat(1,2); System.out.println(r1.equals(r2)); r1 = r2; System.out.println(r1.equals(r2));

  33. Сравняване на обекти. • Ще припокрием метода equals в класа Rat за да можем да сравняваме две рационални числа.За целта ще създадем нов клас Rat1 наследник на Rat но притежаващ нужната функция (обичайна техника е когато даден клас няма необходимите методи да се създаде негов наследник и да се дефинират там).

  34. Задачи за самостоятелна работа • Да се реализира следната йерархия от класове. Абстрактен базов клас фигура в тримерното постранство и функция volume въщаща реално число – обема на фигурата. Наследници: куб задаен с дължина на страната си и цилиндър зададен с мизочина и радиус на основата. Да се напише метод сравняващ обемите на две тела (не се интересуваме от конкретния им вид). Да се създадет подходящи конструктори.

More Related