Predavanje br. index|1|2|3|4|5|6|7|8|9|10|11|12|13|14|HOME
Objektno orijentirano programiranje – primjer: klasa Car – kreiranje objekata uz pomoć operatora new – separator pristupa članovima . – uporaba objekata unutar različitih klasa – inicijaliziranje atributa – metode – pozivanje metoda – implicirani this – member varijable nasuprot lokalnim varijablama – prenošenje argumenata u metodu – prenošenje argumenata u metodu, primjer – setter metode – uporaba setter metoda, primjer – vraćanje vrijednosti iz metode – vraćanje nekoliko vrijednosti iz metoda – uporaba getter metoda, primjer – konstruktori – uporaba konstruktora – ograničenja – zaštita pristupa(access protection) – četiri razine zaštite pristupa – što treba biti public, a što private? – tri koristi od zaštite pristupa – primjer zaštite pristupa – promjena implementacije
U klasičnom proceduralnom programiranju pokušava se problem iz realnog svijeta prikazati pomoću malog broja unaprijed definiranih tipova podataka: cijelih brojeva, realnih brojeva, stringova i eventualno polja. U objektno orijentiranom programiranju kreirate model promatranog sustava realnog svijeta. Klase su tipovi koje programer definira kako bi modelirao dijelove sustava.
Klasa je zamišljena kao prototip, nacrt ili ideja za svoje primjerke (instance). Možete imati cijele i realne brojeve i stringove, ali također imate i automobile, motocikle, ljude, zgrade, oblake, pse, anđele, studente, tečajeve, bankovne račune i bilo kakve tipove koji su bitni za rješavanje zadanog problema.
Klase specificiraju podatke i ponašanje, kako vlastito, tako i objekata koji se iz njih kreiraju. Klasa ima dva dijela: atribute i metode. Atributi opisuju što klasa jest. Metode opisuju što klasa čini.
Koristeći prototip koji klasa predstavlja, možete kreirati proizvoljan broj objekata, a svaki od njih je primjerak (instanca) klase. Različiti objekti iste klase imaju iste atribute i metode, ali vrijednosti atributa bit će općenito različite. Npr. Svi ljudi imaju neku boju očiju, ali se ona razlikuje od čovjeka do čovjeka.
S druge strane, objekt neke klase ima iste metode kao i ostali objekti te klase, osim što metode ovise o vrijednostima svojih argumenata i objektovih atributa.
To se reflektira u runtime obliku objekta. Svaki objekt ima odvojen blok memorije za svoje atribute, ali memorija u kojoj su zabilježene metode zajednička je za sve objekte dane klase.
Pretpostavimo da želimo napisati program za simulaciju prometa koji bilježi prolazak vozila. Na svakom vozilu možemo promatrati svojstva kao što je brzina, maksimalna brzina i registarska oznaka koja ga jednoznačno identificira. U tradicionalnim programskim jezicima imali bismo opisali bismo to pomoću dvije floating point varijable i jednim stringom. U objektno orijentiranom jeziku koristimo koncept klase da bismo podatke spakirali u jedinstveni entitet, npr. ovako:
class Car { String licensePlate; // npr. "New York 543 A23"
double speed; // u kilometrima na sat
double maxSpeed; // u kilometrima na sat
}
Varijable licensePlate, speed i maxSpeed zovemo varijablama instanci,
varijablama članovima ili atributima. Atributi nam kažu što
neka klasa jest i koja su njena svojstva.
Objekt je specifična instanca, primjerak neke klase, sa konkretnim (eventualno promjenljivim) vrijednostima atributa. Dok je klasa općenita zamisao (blueprint) nekih objekata, instanca je konkretni objekt.
Da bismo kreirali konkretni object neke klase, odnosno instancirali
klasu, koristimo ključnu riječ new iza koje slijedi poziv tzv. konstruktora
klase. Pogledajmo kako bismo deklarirali i kreirali novu varijablu tipa
Car koju ćemo nazvati c.
Car c;c =new Car();
Prva riječ, Car, deklarira tip
varijable c. Klase su tipovi pa kad varijablama dodjeljujemo tipove, dodjeljujemo
im zapravo klase te ih deklariramo na isti način kao varijable čiji su tipovi
int, char, double itd.
Znak jednakosti je operator
pridruživanja, a riječ new je operator kreiranja
(instanciranja).
Na kraju, primijetimo metodu Car(). Zagrade naznačuju da je to metoda, a ne tip podataka kao npr. riječ
Car u prvom retku. To je konstruktor, metoda koja kreira novu
instancu klase. O konstruktorima ćet učiti uskoro. Ako svoju klasu i ne
snabdijete konstruktorima, kompajler će umetnuti svoj default konstruktor
bez argumenata.
Deklaraciju tipa i kreiranje instance obično pišemo u jednoj naredbi, npr.
Car c = new Car();
Jednom kad ste kreirali neki objekt, potrebna vam je mogućnost pristupa
njegovim članovima (varijablama
i metodama). Za to ćete upotrijebiti separator pristupa, točku (.). Klasa
Car ima tri atributa:
licensePlate
speed
maxSpeed
Dakle, ako je c objekt tipa Car, c također ima tri odgovarajuće varijable:
c.licensePlate
c.speed
c.maxSpeed
Koristite ih kao što biste koristili bilo koju drugu varijablu. Na primjer:
Car c = new Car(); c.licensePlate = "New York A45 636";
c.speed = 70.0;
c.maxSpeed = 123.45;
System.out.println(c.licensePlate + " se krece brzinom od " +c.speed +
"kilometara na sat.");
Separator . selektira pojedinog člana (varijablu, kao u ovom primjeru, ali također
i metodu) nekog objekta po njegovom imenu.
Sljedeći program kreira novi primjerak automobila (objekta klase Car), dodjeljuje vrijednosti njegovim varijablama i ispisuje rezultat.
class CarTest { public static void main(String args[]) { Car c = new Car(); c.licensePlate = "New York A45 636";
c.speed = 70.0;
c.maxSpeed = 123.45;
System.out.println(c.licensePlate + " se krece brzinom od " +c.speed +
"kilometara na sat."); } }
Ovaj program ne zahtijeva samo klasu CarTest nego također i klasu Car. Da biste ga mogli izvršiti, stavite klasu Car u datoteku Car.java., a klasu CarTest u datoteku CarTest.java. Obje datoteke neka budu u istom direktoriju. Kompilirajte obje
datoteke na uobičajeni način i na kraju izvršite CarTest.
% javac Car.java% javac CarTest.java% java CarTestNew York A45 636 se krece brzinom od 70.0 kilometara na sat.%
Primijetite da klasa Car nema main() metodu, dakle ne možete je “izvršiti”. Ona postoji jedino tako da je
pozivaju drugi programi koji imaju vlastite main() metode.
Mnoge aplikacije koje ćete pisati koristit će više klasa. Uobičajeno je da se svaka klasa stavi u svoju vlastitu datoteku. Uskoro ćete naučiti koristiti i pakete (packages) kako biste mogli organizirati svoje često korištene klase unutar različitih direktorija. Za sada držite sve datoteke sa izvornim programima (*.java) kao i one sa kompiliranim programima (*.class) unutar jednog direktorija. Iako smo kompilirali obje klase odvojeno, dovoljno bi bilo kompilirati samo klasu CarTest jer će kompajler već sam pronaći klasu Car.
Atributi se mogu (i najčešće trebaju) inicijalizirati odmah čim su deklarirani, isto kao i lokalne varijable. Klasu Car možemo preraditi tako da inicijaliziramo njene attribute ovako:
class Car { String licensePlate= ""; // npr. "New York 543 A23"
double speed= 0.0; // u kilometrima na sat
double maxSpeed= 120.0; // u kilometrima na sat
}
Sljedeći program kreira novi automobil (object tipa Car) i ispisuje odgovarajuće podatke.
class CarTest2 { public static void main(String args[]) { Car c = new Car(); System.out.println(c.licensePlate + " se krece brzinom od " + c.speed + "kilometara na sat."); } }
Rezultat izvršavanja bi bio
% javac Car.java% javac CarTest.java% java CarTest se krece brzinom od 0.0 kilometara na sat.%
Tipovi podataka ne znače mnogo ako ne možete s njima ništa napraviti.
Zbog toga postoje metode. Dok atributi kazjuju što klasa jest, metode
kazuju što ona čini. Atribute i metode nazivamo zajedničim imenom
članovima klase. Klase koje ste
do sada upoznali imaju uglavnom samo jednu metodu, main(). Međutim, općenito klase mogu imati mnogo različitih metoda. Na
primjer, klasu Car možemo snabdjeti metodom koja će simulirati vožnju
maksimalnom brzinom:
class Car { String licensePlate = ""; // npr. "New York 543 A23" double speed = 0.0; // u kilometrima na sat double maxSpeed = 120.0; // u kilometrima na sat void floorIt() { // ubrzanje do maksimalne brzine this.speed = this.maxSpeed; } }
Atributi su ostali isti kao prije, ali sad je dodana metoda koju smo
nazvali floorIt(). Počinje ključnom riječi void što je povratni tip
(return type) te metode. Svaka metoda mora imati povratni tip koji može
biti ili void ili neki tip podataka kao int, byte, float, String, ili klasa koju ste sami definirali. Povratni tip pokazuje vrstu
vrijednosti koja će biti vraćena pozivnoj metodi nakon što se pozvana metoda
izvrši. Ako je povratni tip na primjer int, onda tu metodu možete koristiti svagdje gdje biste inače koristili
literal ili varijablu tipa int.Ako je povratni tip void, metoda ne vraća nikakvu vrijednost.
Ime ove metode je floorIt , a iza njega slijede prazne zagrade. Kad bi ova metoda imala
argumente, oni bi se naveli unutar tih zagrada. Tijelo metode nalazi se unutar
vitičastih zagrada.
this.speed =
this.maxSpeed;
Primijetite da smo unutar klase Car koristili ispred imena member varijabli ključnu riječ
this to kako bismo naznačili da su to varijable trenutno aktivnog
objekta.
Izvan klase Car, metodu floorIt() pozvat ćete na isti način kao što ste referencirali attribute, dakle
navodeći ime objekta kojeg želite “ubrzati” i separator ., kao što pokazuje sljedeći primjer
class CarTest3 { public static void main(String args[]) { Car c = new Car(); c.licensePlate = "New York A45 636"; c.maxSpeed = 123.45; System.out.println(c.licensePlate + " se krece brzinom od " + c.speed + " kilometara na sat."); c.floorIt(); System.out.println(c.licensePlate + " se krece brzinom od " + c.speed + " kilometara na sat."); } }
Izlaz:
% javac Car.java% javac CarTest3.java% java CarTest3New York A45 636 se krece brzinom od 0.0 kilometara na sat.New York A45 636 se krece brzinom od 123.45 kilometara na sat.%
Metoda floorIt() je ugrađena u klasu Car. Svaka metoda u Java programu mora, za razliku od C++ programa,
pripadati nekoj klasi.
thisUnutar klase Car nije nužno dodavati imenima atributa prefiks this. jer se on podrazumijeva. To je zato jer metoda floorIt() mora biti pozvana od specifične instance klase Car, a ta instanca zna gdje su njeni podaci. Ili drugim riječima, svaki
object iz klase Car ima svoju vlastitu floorIt() metodu.
class Car { String licensePlate = ""; // npr. "New York 543 A23" double speed = 0.0; // u kilometrima na sat double maxSpeed = 120.0; // u kilometrima na sat void floorIt() { // ubrzanje do maksimalne brzine speed = maxSpeed; } }
U početku, zbog jasnoće, preporučljivo je uvijek eksplicitno koristiti
prefiks this, ali kasnije se od toga može i odustati.
class Car { String licensePlate = ""; // member variabla double speed; = 0.0; // member variabla double maxSpeed; = 120.0; // member variabla boolean isSpeeding() { double excess; // lokalna variabla excess = this.maxSpeed - this.speed; if (excess < 0) return true; else return false; } }
Svi dosadašnji programi bili su vrlo jednostavni. Svaki je imao točno
jednu klasu koja je imala po jednu metodu, main(), i u njoj je bila sadržana sva programska logika i njene vlastite,
lokalne varijable koje nisu
mogle biti referencirane izvan metode.
S druge strane, varijable licensePlate, speed i maxSpeed klase Car class, pripadaju objektu tipa Car, a ne pojedinoj metodi. Definirane su izvan bilo koje metode, ali
unutar klase i nazivaju se member
varijable ili atributi (fields).
Member nije isto što i member varijabla ili atribut. Memberi uključuju i attribute i metode.
Direktno pristupanje atributima smatra se lošom programerskom navikom.
Dobro objektno orijentirano programiranje prakticira pristup poljima isključivo
putem metoda. To vam omogućuje da promijenite implementaciju neke klase bez da
išta mijenjate u njenom sučelju. To vam također omogućuje ugrađivanje raznih
ograničenja na vrijednosti atributa.
Za to je
potrebno imati mehanizam prenošenja informacija u klasu, a to se radi pomoću
argumenata. Na primjer, da bismo dozvolili ostalim objektima da mijenjaju
vrijednost atributa speed na nekom objektu tipa Car, klasu Car možemo snabdijeti metodom koju ćemo nazvati accelerate(). Ta metoda ne dozvoljava pojedinačnom automobilu ubrzavanje iznad
maksimalne brzine ili ispod 0 km/h.
void accelerate(double deltaV) { this.speed = this.speed + deltaV; if (this.speed > this.maxSpeed) { this.speed = this.maxSpeed; } if (this.speed < 0.0) { this.speed = 0.0; } }
Prva linija metode naziva se njenom signaturom.
Signatura void
accelerate(double deltaV) označava da metoda
accelerate() ne vraća nikakvu vrijednost, a uzima jedan argument tipa
double koji će unutar te metode biti označen imenom deltaV. Java prenosi argumente metodama po vrijednosti, ne po referenci.
class Car { String licensePlate = ""; // npr. "New York 543 A23" double speed = 0.0; // u kilometrima na sat double maxSpeed = 120.0; // u kilometrima na sat void floorIt() { // ubrzanje do maksimalne brzine speed = maxSpeed; } void accelerate(double deltaV) { // ubrzanje za zadani deltaV this.speed = this.speed + deltaV; if (this.speed > this.maxSpeed) { this.speed = this.maxSpeed; } if (this.speed < 0.0) { this.speed = 0.0; } } } class CarTest4 { public static void main(String args[]) { Car c = new Car(); c.licensePlate = "New York A45 636"; c.maxSpeed = 123.45; System.out.println(c.licensePlate + " se krece brzinom od " + c.speed + " kilometara na sat."); for (int i = 0; i < 15; i++) { c.accelerate(10.0); System.out.println(c.licensePlate + " se krece brzinom od " + c.speed + " kilometara na sat."); } } }
Izlaz:
% javac Car.java% javac CarTest4.java% java CarTest4New York A45 636 se krece brzinom od 0.0 kilometara na sat.New York A45 636 se krece brzinom od 10.0 kilometara na sat.New York A45 636 se krece brzinom od 20.0 kilometara na sat.New York A45 636 se krece brzinom od 30.0 kilometara na sat.New York A45 636 se krece brzinom od 40.0 kilometara na sat.New York A45 636 se krece brzinom od 50.0 kilometara na sat.New York A45 636 se krece brzinom od 60.0 kilometara na sat.New York A45 636 se krece brzinom od 70.0 kilometara na sat.New York A45 636 se krece brzinom od 80.0 kilometara na sat.New York A45 636 se krece brzinom od 90.0 kilometara na sat.New York A45 636 se krece brzinom od 100.0 kilometara na sat.New York A45 636 se krece brzinom od 110.0 kilometara na sat.New York A45 636 se krece brzinom od 120.0 kilometara na sat.New York A45 636 se krece brzinom od 123.45 kilometara na sat.New York A45 636 se krece brzinom od 123.45 kilometara na sat.New York A45 636 se krece brzinom od 123.45 kilometara na sat.%
Setter metode, zvane također i mutator
metode, imaju zadatak dodjeljivati atributima vrijednosti koje se zadaju putem
argumenata. Ove metode u pravilu vraćaju void. Uobičajeno je koristiti this.name za referenciranje atributa i dodjeljivanje vrijednosti iz istoimenog
argumenta. Na primjer:
class Car { String licensePlate = ""; // npr. "New York 543 A23" double speed = 0.0; // u kilometrima na sat double maxSpeed = 120.0; // u kilometrima na sat // setter metoda za atribut licensePlate void setLicensePlate(String licensePlate) { this.licensePlate = licensePlate; } // setter metoda za atribut maxSpeed void setMaximumSpeed(double maxSpeed) { if (maxSpeed > 0) this.maxSpeed = maxSpeed; else this.maxSpeed = 0.0; } void floorIt() { // ubrzanje do maksimalne brzine speed = maxSpeed; } void accelerate(double deltaV) { // ubrzanje za zadani deltaV this.speed = this.speed + deltaV; if (this.speed > this.maxSpeed) { this.speed = this.maxSpeed; } if (this.speed < 0.0) { this.speed = 0.0; } } }
class CarTest5 { public static void main(String args[]) { Car c = new Car(); c.setLicensePlate("New York A45 636"); c.setMaximumSpeed(123.45); System.out.println(c.licensePlate + " se krece brzinom od " + c.speed + " kilometara na sat."); for (int i = 0; i < 15; i++) { c.accelerate(10.0); System.out.println(c.licensePlate + " se krece brzinom od " + c.speed + " kilometara na sat."); } } }
Izlaz:
% javac Car.java% javac CarTest5.java% java CarTest5New York A45 636 se krece brzinom od 0.0 kilometara na sat.New York A45 636 se krece brzinom od 10.0 kilometara na sat.New York A45 636 se krece brzinom od 20.0 kilometara na sat.New York A45 636 se krece brzinom od 30.0 kilometara na sat.New York A45 636 se krece brzinom od 40.0 kilometara na sat.New York A45 636 se krece brzinom od 50.0 kilometara na sat.New York A45 636 se krece brzinom od 60.0 kilometara na sat.New York A45 636 se krece brzinom od 70.0 kilometara na sat.New York A45 636 se krece brzinom od 80.0 kilometara na sat.New York A45 636 se krece brzinom od 90.0 kilometara na sat.New York A45 636 se krece brzinom od 100.0 kilometara na sat.New York A45 636 se krece brzinom od 110.0 kilometara na sat.New York A45 636 se krece brzinom od 120.0 kilometara na sat.New York A45 636 se krece brzinom od 123.45 kilometara na sat.New York A45 636 se krece brzinom od 123.45 kilometara na sat.New York A45 636 se krece brzinom od 123.45 kilometara na sat.%
Često je korisno da metoda vraća neku vrijednost onoj klasi koja ju je
pozvala. To se radi pomoću ključne riječi return na završetku tijela metode te naznakom povratnog tipa na njenom
početku. Na primjer sljedeća metoda getLicensePlate() vraća trenutačnu vrijednost atributa licensePlate u klasi Car.
String getLicensePlate() {
return this.licensePlate;
}
Ovakve metode koje samo vraćaju vrijednost nekog atributa nazivaju se
getter ili accessor metode. Signatura String
getLicensePlate() nam kaže da metoda
getLicensePlate() vraća vrijednost tipa String i ne traži nikakve argumente. Unutar metode imamo liniju
return this.licensePlate;
koja vraća String sadržan u atributu licensePlate onome tko je metodu pozvao. Povratni tip u return naredbi mora odgovarati deklariranom povratnom tipu u signaturi.
Metoda ne može vratiti više od jedne vrijednosti. Ne možete na primjer
vratiti licensePlate, speed i maxSpeed iz iste metode. Mogli biste ih, naravno, složiti u objekt neke vrste i
njega vratiti, no to nije pravi način. Pravilno bi bilo definirati odvojene
metode, getSpeed(), getMaxSpeed(), i getLicensePlate(), od kojih svaka vraća po jednu odgovarajuću vrijednost.
class Car { String licensePlate = ""; // npr. "New York 543 A23" double speed = 0.0; // u kilometrima na sat double maxSpeed = 120.0; // u kilometrima na sat // getter (accessor) metode String getLicensePlate() { return this.licensePlate; } double getMaxSpeed() { return this.maxSpeed; } double getSpeed() { return this.speed; } // setter metoda za atribut licensePlate void setLicensePlate(String licensePlate) { this.licensePlate = licensePlate; } // setter metoda za atribut maxSpeed void setMaximumSpeed(double maxSpeed) { if (maxSpeed > 0) this.maxSpeed = maxSpeed; else this.maxSpeed = 0.0; } void floorIt() { // ubrzanje do maksimalne brzine speed = maxSpeed; } void accelerate(double deltaV) { // ubrzanje za zadani deltaV this.speed = this.speed + deltaV; if (this.speed > this.maxSpeed) { this.speed = this.maxSpeed; } if (this.speed < 0.0) { this.speed = 0.0; } } }
class CarTest6 { public static void main(String args[]) { Car c = new Car(); c.setLicensePlate("New York A45 636"); c.setMaximumSpeed(123.45); System.out.println(c.getLicensePlate() + " se krece brzinom od "
+c.getSpeed() + " kilometara na sat.");
for (int i = 0; i < 15; i++) { c.accelerate(10.0); System.out.println(c.getLicensePlate() + " se krece brzinom od "
+c.getSpeed() + " kilometara na sat.");
} } }
Primijetite da više nema direktnog pristupa atributima!
Izlaz:
% javac Car.java% javac CarTest5.java% java CarTest5New York A45 636 se krece brzinom od 0.0 kilometara na sat.New York A45 636 se krece brzinom od 10.0 kilometara na sat.New York A45 636 se krece brzinom od 20.0 kilometara na sat.New York A45 636 se krece brzinom od 30.0 kilometara na sat.New York A45 636 se krece brzinom od 40.0 kilometara na sat.New York A45 636 se krece brzinom od 50.0 kilometara na sat.New York A45 636 se krece brzinom od 60.0 kilometara na sat.New York A45 636 se krece brzinom od 70.0 kilometara na sat.New York A45 636 se krece brzinom od 80.0 kilometara na sat.New York A45 636 se krece brzinom od 90.0 kilometara na sat.New York A45 636 se krece brzinom od 100.0 kilometara na sat.New York A45 636 se krece brzinom od 110.0 kilometara na sat.New York A45 636 se krece brzinom od 120.0 kilometara na sat.New York A45 636 se krece brzinom od 123.45 kilometara na sat.New York A45 636 se krece brzinom od 123.45 kilometara na sat.New York A45 636 se krece brzinom od 123.45 kilometara na sat.%
Konstruktor kreira novu instancu klase. On inicijalizira potrebne varijable i obavlja sve poslove koji su potrebni da bi se klasa pripremila za uporabu. Pogledajmo primjer:
Car c =new Car();
Ovdje
je Car() konstruktor klase Car. Konstruktor ima uvijek isto ime kao i pripadna klasa.
Ako klasu ne snabdijemo nikakvim konstruktorom, Java osigurava jedan generički, bez argumenata, tzv. noargs constructor, međutim, bolje je imati vlastite konstruktore. .Konstruktor se radi tako da se napiše metoda koja ima isto ime kao i klasa. Zato se konstruktor klase Car zove Car().
Konstruktori nemaju povratnog tipa. Oni zapravo vraćaju instancu svoje klase, ali to čine implicitno, ne eksplicitno.
Sljedeća metoda je konstruktor koji inicijalizira varijablu koja predstavlja registarsku pločicu (licensePlate) na prazan string, brzinu (speed) na nulu, a maksimalnu brzinu (maxSpeed) na 120.0 km/h.
Car() { this.licensePlate = ""; this.speed = 0.0; this.maxSpeed = 120.0; }
Još bolje, možete napisati konstruktor koji prima tri argumenta i koristi ih za inicijaliziranje odgovarajućih varijabli:
Car(String licensePlate, double speed, double maxSpeed) {
this.licensePlate = licensePlate; this.speed = speed; if (maxSpeed > 0) this.maxSpeed = maxSpeed; else this.maxSpeed = 0.0; if (speed > this.maxSpeed) this.speed = this.maxSpeed; if (speed < 0) this.speed = 0.0; else this.speed = speed; }
Ili možda želite da inicijalna brzina uvijek bude jedanaka nuli, a maksimalna brzina i registarska pločica specificirane argumentima:
Car(String licensePlate, double maxSpeed) {
this.licensePlate = licensePlate; this.speed = 0.0; if (maxSpeed > 0) this.maxSpeed = maxSpeed; else this.maxSpeed = 0.0; }
Preradimo još jednom klasu Car, tako da u nju ugradimo ove konstruktore:
class Car { String licensePlate; // npr. "New York 543 A23" double speed; // u kilometrima na sat double maxSpeed; // u kilometrima na sat Car() { this.licensePlate = ""; this.speed = 0.0; this.maxSpeed = 120.0; } Car(String licensePlate, double speed, double maxSpeed) { this.licensePlate = licensePlate; this.speed = speed; if (maxSpeed > 0) this.maxSpeed = maxSpeed; else this.maxSpeed = 0.0; if (speed > this.maxSpeed) this.speed = this.maxSpeed; if (speed < 0) this.speed = 0.0; else this.speed = speed; } Car(String licensePlate, double maxSpeed) { this.licensePlate = licensePlate; this.speed = 0.0; if (maxSpeed > 0) this.maxSpeed = maxSpeed; else this.maxSpeed = 0.0; } // getter (accessor) metode String getLicensePlate() { return this.licensePlate; } double getMaxSpeed() { return this.maxSpeed; } double getSpeed() { return this.speed; } <