Книга е още в много ранна фаза на написване


Методи, аргументи и връщани стойности



страница19/73
Дата25.07.2016
Размер13.53 Mb.
#6732
1   ...   15   16   17   18   19   20   21   22   ...   73

Методи, аргументи и връщани стойности


До сега терминът функция бе използван за означаване на именувана под­про­гра­ма. По-обичайния термин в Javaе метод, както в “начин да се направи нещо.” Ако искате, може да продължите да мислите в термините на функции. Раз­ли­ка­та е само синтактична, но от сега нататък в книгата ще се идползва “метод” а не “функ­ция.”

Методите в Java определят съобщенията, които обектът може да приема. В тази сек­ция ще научите колко просто е да се създават методи.

Основните части на метода са името, аргументите, връщаната стойност и тя­ло­то. Ето основната форма:

returnType methodName( /* списък аргументи */ ) {


/* Тяло на метода */
}

Връщаният тип е типът на променливата, която изскача от метода след не­го­во­то извикване. Името, както се досещате, го идентифицира. Списъкът аргументи по­каз­ва нещата, които се дават на метода и типа им.

В Java методи могат да се създават само като част от клас. Метод може да се ви­ка само за обект3 и този метод трябва да може да осъществи извикването. Ако се опитате да извикате неправилен метод на обектще получите грешка при ком­пилация. Методът се вика подобно както се означават член-променливите, как­то тук: objectName.methodName(arg1, arg2, arg3). Да предположим на­при­мер че имате метода f( ) който не приема аргументи и връща int. Тогава ако има­те обект наречен a за който f( ) може да бъде извикан, това може да стане та­ка:

int x = a.f();

Типът на връщане трябва да е съвместим с типа на x.

Актът на извикване на метод общоприето се означава като изпращане на съоб­ще­ние към обект. В горния пример съобщението е f( ) и обектът е a. ОО про­гра­ми­ране често в резюме се изразява с “изпращане съобщения на обекти.”


Списъкът аргументи


Списъкът аргументи на метода задава каква информация може да му се дава при извикване. Както можете да познаете тази информация – както всичко дру­го в Java – има формата на обект. Такаче трябва да зададете вида на обектите и име­ната, които ще се използват. Както във всяка ситуация в Java с обекти фак­ти­чески се предават манипулатори.4 Типът на манипулатора трябва да бъде то­чен, обаче. Ако аргументът се предполага да е String това, което давате трябва да е стринг.

Да кажем че един метод взима за аргумент стринг. Ето какво трябва да се сло­жи в дефиницията на класа, за да бъде компилирано:

int storage(String s) {
return s.length() * 2;
}

Този метод казва колко байта трябват за да се вмести информацията от кон­кре­тен стринг String. (Всеки char в String е 16 бита, или два байта дълъг, за да под­дър­жа Unicode знаци.) Аргументът е от тип String и е наречен s. Щом s е даден на метода, може да го третирате като всеки друг обект. (Може да му изпращате съоб­щения.) Тук length( ) метода се извиква, който е един от методите на Strings; той връща броя на знаците в стринга.

Може да видите също използвана ключовата дума return която прави две неща. Пър­во тя значи “излез от метода, свършихме.” Второ, ако методът произвежда стой­ност, тази стойност се слага точно след return оператора. В този случай връ­щаната стойност се дава с s.length( ) * 2.

Може да се връща всякакъв тип, но ако не щете да се връща нищо, показвате го с декларация на метода като void. Ето примери:

boolean flag() { return true; }

float naturalLogBase() { return 2.718f; }

void nothing() { return; }

void nothing2() {}

Когато типът на връщане е void, ключовата дума return се използва само да се из­лезе от метода и затова не е необходима, ако стигнете края на метода. Може да излезете от всяка точка на метода, но ако сте дали тип на връщане не-void ком­пилаторът ще осигури верния тип независимо къде излизате.

В този момент може да изглежда, че програмата е само обекти, чиито методи взе­мат за аргументи други обекти и това е всичко. Това разбира се е повечето от работата, но в следващата глава ще научите как да вършите работата на нис­ко ниво, вземайки решения в методите. За тази глава изпращането на съоб­ще­ния стига.


Построяване на Java програма


Има няколко други неща които трябва да резберете, преди да видите своята пър­ва Java програма.

Видимост на имената


Управлението на имената е проблем във всеки програмен език. Ако използвате име в даден модул и друг програмист го използва в друг модул, как ще ги раз­личните и предотвратите “сблъскването”? В C това особено е проблем, понеже че­сто програмите са неуправляемо море от имена. C++ класовете (на които са ба­зирани Java класовете) вместват функциите в класовете ("манглинг" на име­на­та - б.пр.) така че не може да се получи сблъсък с имената в друг клас. Обаче C++ позволяма и глобални данни и глобални функции, така че то все още е въз­мож­но. За да реши проблема C++ въвежда namespaces използвайки до­пъл­ни­тел­ни ключови думи.

Java можа да избегне проблема чрез свеж подход. За да произведе не­дву­смис­ле­но име за библиотека, използвания спецификатор прилича на домейново име в Мрежата. Фактимески създателите на Java искат да използвате домейновото си име отзад напред, понеже тези имена са уникални. Щом моето домейново име е BruceEckel.com, моята библиотека от foibles би била наречена com.bruceeckel.utility.foibles. След обърнатата дамейново име точките пред­ста­вля­ват поддиректории.

В Java 1.0 и Java 1.1 домейновите разширения com, edu, org, net и т.н. са с главни букви по договаряне, така че името щеше да бъде: COM.bruceeckel.utility.foibles. При разработването на Java 2 беше обаче от­кри­то че това създава проблеми и сега цялото име на библиотеката е с малки бук­ви.

Този механизъм в Java означава, че всичките ви файлове имат отделни про­стран­ства на имената и всеки клас във файл има уникален идентификатор. (Име­на­та на класове в един файл трябва да са уникални, разбира се.) Така че не се на­лага да учите специални черти на езика за да го осигурите - механизмът го оси­гурява заради вас.


Използване на други компоненти


Щом поискате да използвате предварително дефиниран клас във вашата про­гра­ма, компилаторът трябва да знае къде да го намери. Разбира се класът би мо­гъл да съществува в същия сорс, откъдето се използва. В този случай просто го използвате, даже и да е определен по-късно (от мястото на използване - б.пр.) във файла. Java премахва проблема “forward referencing” така че няма за­що да мислите за него.

Как ще е ако класът е определен в друг файл? Мже да си помислите, че ком­пи­ла­торът е достатъчно умен да го потърси и намери, но има проблем. Да до­пус­нем, че искате клас с определено име, но дефиниция за клас с такова име има в по­вече от един файл. Или още по-лошо, да допуснем че пишете програма и сла­га­те в библиотека клас, чието име се дублира с името на клас, който вече е в би­блио­теката.

За да се реши въпросът трябва да се премахнат всички потенциални дву­смис­лия. Това се прави чрез указване на Java точно кои класове искате чрез клю­чо­ва­та дума import. import казва на компилатора да вземе package, което е би­блио­тека от класове. (В други езици библиотеката би съдържала също и данни и функ­ции, но помним, че в Java всичко е в рамките на класове.)

Повечето пъти ще използвате класове от стандартните библиотеки на Java кои­то идват с компилатора. С тях няма нужда да се безпокоите с дълги, обърнати до­мей­нови имена; просто пишете, например:

import java.util.ArrayList;

за да кажете на компилатора че искате класа на Java ArrayList. Обаче util може да съдържа множество класове и вие да искате да ги използвате без да ги зая­вя­ва­те един по един. Това лесно се прави чрез използване на ‘*’ за индикация:

import java.util.*;

По-общоприето е да се импортира колекция от класове по този начин, откол­ко­то отделни класове.


Ключовата дума static


Нормално като създавате клас описвате как обектите ще изглеждат и какво по­ве­дение ще имат. Фактически нищо не става, докато не създадете клас с new и чак след това са достъпни променливите и методите.

Има две ситуации, където този подход е недостатъчен. Едната е когато искате да има единствени данни за много обекти, без значение колко има създадени и да­же ако няма. Другата е ако ви трябва метод, който не е асоцииран с никой клас. Тоест метод, който може да се вика ако няма създадени класове. Може да по­стигнете и двата ефекта с ключовата дума static. Когато напишете че нещо е static това значи че нещото не е свързано с никакъв конкретен екземпляр (обект - б.пр.) на този клас. Така че и да не сте създали обект може да викате static ме­тод или да използвате static данни. С обикновените, не-static данни и методи тряб­ва да създадете обект и да използвате именно неговите данни и методи, по­неже за не-static данни и методи трябва да се знае с кой точно обект работят. Раз­бира се, тъй като static методите не изискват да е създаден обект за да бъдат из­ползвани, те не могат направо да имат достъп до не-static членове и методи чрез просто извикване без споменаване на имената им (тъй като не-static чле­но­ве­те и методите трябва да са свързани с конкретен обект).

Някои ОО езици използват термините class data и class methods, което значи че дан­ните и методите са на категорията на класа, а не на отделен обект. Понякога ли­тературата за Java използва същите термини.

За да се направи член-променлива static, просто се слага ключовата дума пред де­финицията. Примерът прави static член и го инициализира:

class StaticTest {

static int i = 47;

}

Сега и да направите два StaticTest обектаще има една и съща памет за StaticTest.i. За двата обекта I е общо. Нека:



StaticTest st1 = new StaticTest();

StaticTest st2 = new StaticTest();

В тази точка и st1.i и st2.i имат една и съща стойност 47 понеже я вземат от едно и също място в паметта.

Има два начина за споменаване на static променлива. Както е по-горе, може да е с името на обект, st2.i. Може също и направо чрез името на класа, което не мо­же да се направи с не-статичните. (Това е предпочитаният начин, доколкото под­чертава статичната природа на static променливата.)

StaticTest.i++;

Операторът ++ инкрементира променливата. В тази точка и st1.i и st2.i ще имат стойност 48.

Подобна логика се прилага към статичните методи. Може да се обръщате към тях чрез обекта, както и към всеки метод или да използвате допълнителния син­так­сис classname.method( ). Статичният метод се дефинира по подобен начин:

class StaticFun {

static void incr() { StaticTest.i++; }

}

Може да се види че StaticFun методът incr( ) инкрементира static данната i. Може да се извика incr( ) по типичния начин, чрез обект:



StaticFun sf = new StaticFun();

sf.incr();

Или, понеже incr( ) е статичен метод, чрез името на класа:

StaticFun.incr();

Докато static, приложен към член-данни определено променя начина по който се създават данните (една за всички класове срещу една за всеки обект в не-static случая), приложена към методи не е толкова драматична промяната. Важ­но приложение на static за методи е да позволи да се използват методи без съз­да­ване на обект. Това е съществено, както ще видим, при създаването на main( ) ме­тода, който е входната точка за стартиране на програмата.

Като всеки метод и static методът може да създава и използва обекти от него­вия си тип, така че static методът често се използва за “овчар” на стадото от екзем­пляри от неговия си тип.





Сподели с приятели:
1   ...   15   16   17   18   19   20   21   22   ...   73




©obuch.info 2024
отнасят до администрацията

    Начална страница