Садржај
2 Класе и објекти
2.1 Основни појмови о класама и објектима
3 Генеричке класе
4 Наслеђивање и полиморфизам
5 Примери пројеката са решењима
5.1 Различита кретања
5.2 Квиз
5.4 Приказ рада алгоритама сортирања

Генеричке класе и методи

У овој лекцији:

  • зашто су генеричке класе боље од обичних,

  • како да правимо своје генеричке класе,

  • шта су генерички методи и како да их пишемо,

  • апстрактни типови податка и њихова веза са генеричким класама.

Предности генеричких класа

Када би се у библиотеци уместо генеричке класе List налазиле конкретне (негенеричке, обичне) класе IntList, CharList, StringSlist и друге, такав приступ би имао две велике мане:

  • било би потребно да се пише и одржава више класа у којима постоји много сличности, што је неки облик понављања кода, за који смо више пута истицали зашто је непожељан;

  • не би биле подржане листе објеката чију класу ми дефинишемо, односно било каквих специфичних, или накнадно дефинисаних класа.

Видимо да је велика предност генеричких класа у односу на обичне то, што уз мање писања кода у коришћеној класи или класама, добијамо више функционалности као корисници тих класа.


На генеричке класе можемо да гледамо као на један начин повећавања поновне употребљивости (енгл. reusability) једном написаног кода, без даљих измена тог кода.

Други начини да се оствари поновна употребљивост кода обухватају наслеђивање класа, о чему ће бити речи у наредном поглављу, као и издвајање кода у библиотеке, о чему смо већ говорили.

Још неке добре стране генеричких класа

Идеја да се одређени алгоритми (функције, методи) напишу тако да могу да се примене на различите типове података је прилично стара и није одмах реализована кроз концепт генеричких класа, већ је имала свој развојни пут. Некада је функционалност коју доносе генеричке класе – колекције симулирана у разним програмским језицима тако што су коришћени објекти најопштијег типа Object, или неког сличног имена (у раним верзијама језика C# коришћена је класа ArrayList, која је одавно превазиђена). Овакав приступ је лошији од генеричких класа из бар два разлога.

  • Исправност стварног типа објеката не може да се провери у време компајлирања, него тек у време извршавања, јер општи објекти могу да садрже податке било ког типа, а колекције таквих објеката могу чак да садрже податке различитих типова. Ово оставља простор за многе грешке при извршавању (багове), који се теже откривају и исправљају него грешке при компајлирању.

  • Провера слагања типова при операцијама над објектима у току извршавања програма чини програм споријим него што би могао да буде (да је провера обављена у време компајлирања).

Према томе, у предности генеричких класа и метода у односу на претходна слична решења можемо да убројимо:

  • безбедност типова (енгл. type safety), јер се слагање типова при операцијама код генеричких класа проверава статички, тј. у време компајлирања. Ово је у случају генеричких класа изводљиво, јер за разлику од решења у коме се користе општи објекти, компајлер тачно зна који тип података се користи на сваком месту.

  • боље перформансе у односу на решења са општим објектима. Употребом генеричких класа избегава се потреба за конверзијом променљивих простог типа у објекте (тзв. боксовање, енгл. boxing), распакивањем из објеката назад у променљиве (unboxing) и провером типа у време извршавања. На пример, генеричка листа целих бројева садржи само целе бројеве, а не објекте који садрже целе бројеве.

Генеричке класе које дефинише корисник

Ми такође можемо да пишемо генеричке класе. На пример, када у библиотеци .NET не би постојала класа Stack, могли бисмо да је напишемо овако:

Програм који демонстрира употребу класе CustomStack, исписује

d
c
b
a

Видимо да се писање генеричких класа врло мало разликује од писања конкретних класа. У ствари, једина разлика је то што се појављује за сада неодређени (општи, генерички) тип T, али он се користи на потпуно исти начин, на који бисмо користили int, char, double или било који други конкретан тип. Ознака T за општи тип је уобичајена, мада уместо ње може да се користи било који идентификатор, који у ту сврху уведемо.

Генерички методи

Генерички тип не мора да буде параметар целе класе, јер у оквиру обичне класе можемо да пишемо појединачне методе са генеричким типом као параметром, тј. генеричке методе. На пример, ако нам је често потребан метод којим две променљиве или два објекта одређеног типа размењују вредности, можемо да напишемо генерички метод Swap на следећи начин:

Програм исписује:

2, 1
dva, jedan

Пример илуструје могућност да се помоћу метода Swap размењују вредности било ког типа, јер је метод једном употребљен за целе бројеве, а други пут за стрингове.

Апстрактни типови података

Апстрактан тип података (енгл. abstract data type, ADT) је чисто теоријски, формалан појам, који нема везе са конкретним програмским језицима. Он описује одређени тип података (често колекцију простијих објеката) са становишта корисника, тј. описује шта може да се ради са објектима тог типа. Апстрактан тип се не бави конкретним начином представљања података у рачунару, нити начином остваривања описане функционалности, што би представљало тачку гледишта имплементатора, а не корисника.

Добар, и опште познат пример онога што се у рачунарству назива апстрактан тип података је скуп. У математици се скупови не дефинишу, али су детаљно описане основне релације (једнакост, подскуп) и операције (унија, пресек, а у извесним контекстима и комплемент) над скуповима, као и особине тих релација и операција (нпр. асоцијативност унирања скупова). Према том опису, скупове замишљамо као колекције било каквих објеката, над којима могу да се изводе те основне операције, односно да се провери да ли су два дата скупа у некој од основних релација.

Класични примери апстрактних типова података који се често срећу у рачунарству су стек (stack), ред (queue), хрпа или хип (heap), двострани ред (double ended queue), бинарно дрво (binary tree) и други. На пример, стек као апстрактан тип се описује као колекција било каквих објеката, над којом могу да се врше операције стави и узми, с тим да се операцијом узми са стека увек узима оно што је последње стављено. Стек као апстрактан тип се сматра бесконачним, тј. не разматра се могућност прекорачења стека. Напоменимо да сви апстрактни типови података имају и потпуно формалан, математички опис, у који овде немамо потребе да се упуштамо.

Веза апстрактних типова и генеричких класа

Одређени апстрактан тип података може да буде имплементиран у неким програмским језицима, а у другим да не буде. При томе свака имплементација само мање или више приближно одговара математичком моделу апстрактног типа, што због ограничених могућности рачунара (пре свега коначне меморије), што због недовољног нивоа апстракције (нпр. функционише само за одређени тип елемената колекције). Мада је апстрактан тип најчешће немогуће имплементирати у идеалном облику, постојеће имплементације су углавном довољно добре за практичне потребе.

Пошто се код апстрактних типова података који представљају колекције (скуп, стек итд.) не прецизира тип елемената колекције, генеричке класе се појављују као погодно и моћно средство за имплементацију апстрактних типова података.

Скривањем имплементације у приватан део класе добро се опонаша представа о апстрактном типу као формалном, теоријском појму, неоптерећеном имплементацијом. Додатно, употребом генеричких типова добро се опонаша још једна суштинска особина апстрактних типова, а то је занемаривање природе (типа, врсте) садржаја колекција описаних помоћу апстрактног типа.

(Created using Swinx, RunestoneComponents and PetljaDoc)
© 2022 Petlja
A- A+