Predavanje br. index|1|2|3|4|5|6|7|8|9|10|11|12|13|14|HOME


Četvrto predavanje – još o klasama i objektima

Što je overloading? – ključna riječ this u konstruktorima – nasljeđivanje – nadklasa (superclass), MotorVehicle – podklase (subclasses), Motorcycle i Car – podklase i polimorfizam – kaskadno nasljeđivanje – statičke varijable i metode – pozivanje statičkih metoda – ključna riječ final – prekrivanje metoda (overriding) – ispis objekata pomoću toString() metoda – ključna riječ abstract – sučelja (interfaces) – implementiranje sučelja – implementiranje sučelja Cloneable – metoda equals()  - metoda hashCode() iz java.lang.Object – unutarnje klase (inner classes) – iznimke (exceptions) – try-catch blok – što možemo učiniti s uhvaćenom iznimkom? – ključna riječ finally – razne vrste iznimaka – hvatanje višestrukih iznimaka – izbacivanje iznimke, ključna riječ throws – pisanje vlastitih klasa iznimaka – metode klase Exception – biblioteka klasa – dokumentiranje vlastitih programa – importiranje klasa i paketa – primjeri metoda iz klase java.lang.Math – klasa java.util.Random – klasa java.lang.String – pisanje vlastitih paketa – JAR arhive


Što je overloading?

Izraz overloading označava situaciju kad se ista metoda ili operator koristi na više različitih tipova podataka. Na primjer, znakom + se označava zbrajanje cijelih brojeva kao i konkatenacija stringova, pri čemu se on na različitim tipovima podataka ponaša različito. Zato kažemo da je znak + overloaded.

Metode također mogu biti overloaded. Na primjer  System.out.println() može ispisivati podatke tipa double, float, int, long, String i tako dalje, a koristite je na potpuno isti način na svim tim tipovima podataka.

Normalno jedan identifikator referencira točno jednu metodu ili konstruktor. Međutim kad jedan identifikator označava više od jedne metode ili konstruktora, to je overloading.

Koju metodu identifikator zaista referencira vidi se iz njezine signature, dakle broja, tipa i poretka argumenata koji se toj metodi prenose. Signatura prvog od naših konstruktora je Car(), signatura drugog Car(String, double, double), a trećeg Car(String, double). Dakle kad se konstruktor pozove sa jednim argumentom tipa String i jednim tipa double, pozvat će se njegova treća varijanta.

Primijetite da smo konstruktor bez argumenata, koji je inače default kad nema drugih konstruktora, ovdje eksplicitno dodali, jer u prisustvu drugih konstruktora on više nije default i pozivanje bez argumenata izazvalo bi grešku. Grešku će izazvati i pozivanje konstruktora sa krivim brojem ili poretkom argumenata. Na primjer

 
Car c = new Car(100.0);
 

izazvat će pogrešku kod kompiliranja:

 
Error:    Method Car(double) not found in class Car.
Car.java  line 17    
%

Neki objektno orijentirani jezici, npr C++ dozvoljavaju da i operatori poput + ili – budu overloaded. To je korisno kad se radi sa korisnički definiranim matematičkim klasama kao što su kompleksni brojevi i slično. Međutim, većina nematematičkih klasa nema evidentno značenje za takve operatore, a pokazalo se da overloaded operatori otežavaju timski rad na velikim programskim projektima. Zato Java ne podržava koncept overloaded operatora.


Ključna riječ this u konstruktorima

Klase koje rade programeri mogu također sadržati overloaded metode. Možete imati metode s istim imenom, ali različitim listama argumenata. Na primjer, vidjeli smo tri različita konstruktora klase Car, jedan sa tri argumenta, drugi sa dva i treći bez argumenata.

Česta je praksa da overloaded metode budu suštinski iste, ali neka od njih definira default vrijednosti za jedan ili više argumenata. U tom slučaju dobro je (iako neznatno sporije) da svu programsku logiku stavite u metodu koja uzima najviše argumenata i onda jednostavno pozivate tu metodu iz svih overloaded varijanti koje uglavnom popunjavaju odgovarajuće default vrijednosti.

Ta tehnika je pogodna i kad neku metodu treba napraviti u dvije varijante koje podržavaju različite tipove. Na primjer, jedna varijanta može konvertirati String u int i onda pozvati drugu varijantu koja uzima int kao argument.

To funkcionira bez daljnjega za obične metode, ali konstruktori ne mogu tek tako pozivati jedni druge. Na primjer, ovo nije legalno:

  public Car(String licensePlate, double maxSpeed) {
 
    Car(licensePlate, 0.0, maxSpeed); //ovo nije legalno unutar konstruktora!!!
    
  }
 
 

Za pozivanje drugog konstruktora iste klase koristi se ključna riječ this.

 
  public Car(String licensePlate, double maxSpeed) {
 
    this(licensePlate, 0.0, maxSpeed);
    
  }
 
public class Car {
 
  private String licensePlate; // npr. "New York 543 A23"
  private double speed;        // u kilometrima na sat
  private double maxSpeed;     // u kilometrima na sat
  
  // konstruktori
  public Car() {
    this("", 0.0, 120.0);
  }
 
  public Car(String licensePlate, double maxSpeed) {
 
    this(licensePlate, 0.0, maxSpeed);
    
  }
 
  public 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;
    
  }
 
  // getter (accessor) metode
  
  public String getLicensePlate() {
    return this.licensePlate;
  }
 
  public double getMaxSpeed() {
    return this.maxSpeed;
  }
 
  public double getSpeed() {
    return this.speed;
  }
 
  // setter metoda za atribut licensePlate
  public void setLicensePlate(String licensePlate) {
    this.licensePlate = licensePlate;
  }
 
  // setter metoda za atribut maxSpeed
  public void setMaximumSpeed(double maxSpeed) {
    if (maxSpeed > 0) this.maxSpeed = maxSpeed;
    else this.maxSpeed = 0.0;
  }
 
  public void floorIt() { // ubrzanje do maksimalne brzine
    speed = maxSpeed;  
  }
  
  public 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; 
     }     
     
  }
  
}
 

Ovakav pristup štedi linije koda. Također, ako se kasnije pokaže potreba za promjenom ograničenja ili nekih drugih aspekata konstrukcije automobila, trebat će mijenjati jednu, a ne dvije metode. To ne samo da je lakše nego je i vjerojatnost pojave pograšaka zbog nekonzistentnog modificiranja metoda manja.


Nasljeđivanje

Smatra se da je mogućnost višestrukog korištenja koda (code reusability) ključna prednost objektno orijentiranih jezka nad tradicionalnim. Nasljeđivanje je mehanizam koji to omogućuje. Objekt može naslijediti varijable i metode od drugog objekta. Može zadržati one koje mu trebaju, a zamijeniti one koje mu ne trebaju.

Pokazat ćemo to u nekoliko koraka. Za početak, proširimo klasu Car atributima koji opisuju proizvođača, model, godinu, broj putnika, broj kotača za koji ćemo unaprijed reći da je 4, broj vrata za koji stavimo da može biti 2 ili 4. Takva klasa bi mogla izgledati ovako:

public class Car {
 
  private String licensePlate; // npr. "New York 543 A23"
  private double speed;        // u kilometrima na sat
  private double maxSpeed;     // u kilometrima na sat
  private String make;              // npr. "Ford"
  private String model;             // npr. "Taurus"
  private int    year;              // npr. 1997, 1998, 1999, 2000, 2001, itd.
  private int    numberPassengers;  // npr. 4
  private int    numberWheels = 4;  // svi automobili imaju 4 kotaca
  private int    numberDoors;       // npr. 4
  
  // konstruktori
 
  public Car() {
    this("", 0.0, 120.0, "", "", 2001, 4,4);
  }
 
  public Car(String licensePlate, double maxSpeed) {
    this(licensePlate, 0.0, maxSpeed, "", "", 2001, 4,4);
  }
 
  public Car(String licensePlate, double maxSpeed,
   String make, String model, int year, int numberOfPassengers,
   int numberOfDoors) {
 
    this(licensePlate, 0.0, maxSpeed, make, model, year, 
     numberOfPassengers, numberOfDoors);
    
  }
 
  public Car(String licensePlate, double speed, double maxSpeed,
   String make, String model, int year, int numberOfPassengers) {
 
    this(licensePlate, speed, maxSpeed, make, model, year, 
     numberOfPassengers, 4);
    
  }
 
  public Car(String licensePlate, double speed, double maxSpeed,
   String make, String model, int year, int numberOfPassengers,
   int numberOfDoors) {
 
    this.licensePlate = licensePlate; 
    this.make = make; 
    this.model = model; 
    this.year = year; 
    this.numberPassengers = numberOfPassengers; 
    this.numberDoors = numberOfDoors; 
 
    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;
    
  }
  
  // getter (accessor) metode
  public String getLicensePlate() {
    return this.licensePlate;
  }
 
  public String getMake() {
    return this.make;
  }
 
  public String getModel() {
    return this.model;
  }
 
  public int getYear() {
    return this.year;
  }
  
  public int getNumberOfPassengers() {
    return this.numberPassengers;
  }
  
  public int getNumberOfWheels() {
    return this.numberWheels;
  }
  
  public int getNumberOfDoors() {
    return this.numberDoors;
  }
  
  public double getMaxSpeed() {
    return this.maxSpeed;
  }
 
  public double getSpeed() {
    return this.speed;
  }
 
  // setter metoda za atribut licensePlate
  public void setLicensePlate(String licensePlate) {
    this.licensePlate = licensePlate;
  }
 
  // setter metoda za atribut maxSpeed
  public void setMaximumSpeed(double maxSpeed) {
    if (maxSpeed > 0) this.maxSpeed = maxSpeed;
    else this.maxSpeed = 0.0;
  }
 
  public void floorIt() { // ubrzanje do maksimalne brzine
    speed = maxSpeed;  
  }
  
  public 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; 
     }     
     
  }
 
  public String toString() { // ispis podataka o automobilu
    return ("[Automobil: oznaka=" + this.licensePlate 
     + " brzina=" + this.speed +  "Max. brzina=" + this.maxSpeed +"]");
  }
 
  
}

Nadklasa (superclass) - MotorVehicle

Definirat ćemo sada općenitiju klasu MotorVehicle koja opisuje motorna vozila.

 
public class MotorVehicle {
 
  protected String licensePlate; // npr. "New York 543 A23"
  protected double speed;        // u kilometrima na sat
  protected double maxSpeed;     // u kilometrima na sat
  protected String make;              // npr. "Ford"
  protected String model;             // npr. "Taurus"
  protected int    year;              // npr. 1997, 1998, 1999, 2000, 2001, itd.
  protected int    numberPassengers;  // npr. 4
  //izostavljen je atribut numberWheels 
  //izostavljen je atribut numberDoors 
  
  // konstruktori
  public MotorVehicle(String licensePlate, double maxSpeed,
   String make, String model, int year, int numberOfPassengers) {
    this(licensePlate,0.0, maxSpeed, make, model, year, numberOfPassengers);    
  }
 
  public MotorVehicle(String licensePlate, double speed, double maxSpeed,
   String make, String model, int year, int numberOfPassengers) {
 
    this.licensePlate = licensePlate; 
    this.make = make; 
    this.model = model; 
    this.year = year; 
    this.numberPassengers = numberOfPassengers; 
 
    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;
    
  }
  
  // getter (accessor) metode
  public String getLicensePlate() {
    return this.licensePlate;
  }
 
  public String getMake() {
    return this.make;
  }
 
  public String getModel() {
    return this.model;
  }
 
  public int getYear() {
    return this.year;
  }
  
  public int getNumberOfPassengers() {
    return this.numberPassengers;
  }
  
//izostavljena je metoda getNumberOfWheels()
  
//izostavljena je metoda gdtNumberOfDoors()
  
  public double getMaxSpeed() {
    return this.maxSpeed;
  }
 
  public double getSpeed() {
    return this.speed;
  }
 
  // setter metoda za atribut licensePlate
  protected void setLicensePlate(String licensePlate) {
    this.licensePlate = licensePlate;
  }
 
  // setter metoda za atribut maxSpeed
  protected void setMaximumSpeed(double maxSpeed) {
    if (maxSpeed > 0) this.maxSpeed = maxSpeed;
    else this.maxSpeed = 0.0;
  }
 
  public void floorIt() { // ubrzanje do maksimalne brzine
    speed = maxSpeed;  
  }
  
  public 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; 
     }     
     
  }
  
}
 

Klasa MotorVehicle ima sve zajedničke karakteristike motocikala i automobila, ali ne specificira broj kotača, numberWheels, a također nema ni varijablu numberDoors budući da ne moraju sva motorna vozila imati vrata. Primijetite da su metode setLicensePlate() setMaximumSpeed() sada protected, a ne više private ili public. To je zato da bi im se moglo pristupiti iz podklasa.


Podklase (subclasses)Motorcycle i Car

Definirat ćemo sada dvije podklase od MotorVehicle, klasu Motorcycle koja opisuje motorkotače i Car koja opisuje automobile. Koristimo ključnu riječ extends.

public class Motorcycle extends MotorVehicle {
 
  protected int numberWheels = 2;  
  
  // konstruktori
  public Motorcycle(String licensePlate, double maxSpeed,
   String make, String model, int year, int numberOfPassengers) {
    this(licensePlate, 0.0, maxSpeed, make, model, year, numberOfPassengers);    
  }
 
  public Motorcycle(String licensePlate, double speed, double maxSpeed,
   String make, String model, int year, int numberOfPassengers) {
   
    // pozovemo konstruktor nadklase. tj. klase MotorVehicle
    super(licensePlate, speed, maxSpeed, make, model, year, 
     numberOfPassengers);   
  }
  
  public int getNumberOfWheels() {
    return this.numberWheels;
  }
    
}
 
public class Car extends MotorVehicle {
 
  protected int numberWheels = 4;  
  protected int numberDoors;
  
  // konstruktori
 
  public Car() {
    this("", 0.0, 120.0, "", "", 2001, 4,4);
  }
 
  public Car(String licensePlate, double maxSpeed) {
    this(licensePlate, 0.0, maxSpeed, "", "", 2001, 4,4);
  }
 
  public Car(String licensePlate, double maxSpeed,
   String make, String model, int year, int numberOfPassengers,
   int numberOfDoors) {
    this(licensePlate, 0.0, maxSpeed, make, model, year, numberOfPassengers, 
     numberOfDoors);    
  }
 
  public Car(String licensePlate, double speed, double maxSpeed,
   String make, String model, int year, int numberOfPassengers) {
    this(licensePlate, speed, maxSpeed, make, model, year, 
     numberOfPassengers, 4);    
  }
 
  public Car(String licensePlate, double speed, double maxSpeed,
   String make, String model, int year, int numberOfPassengers,
   int numberOfDoors) {
    super(licensePlate, speed, maxSpeed, make, model,
     year, numberOfPassengers);
    this.numberDoors = numberOfDoors;
  }
   
  public int getNumberOfWheels() {
    return this.numberWheels;
  }
 
  public int getNumberOfDoors() {
    return this.numberDoors;
  }
 
  public String toString() { // ispis podataka o automobilu
    return ("[Automobil: oznaka=" + this.licensePlate 
     + " brzina=" + this.speed +  "Max. brzina=" + this.maxSpeed +"]");
  }
    
}
 

Klase Motorcycle i Car nasljeđuju sve karakteristike klase MotorVehicle. Nemaju iste konstruktore, ali pozivaju konstruktore svoje nadklase pomoću ključne riječi super.


Podklase i polimorfizam

Klase Car i Motorcycle su podklase od MotorVehicle. Ako instancirate klasu Car ili Motorcycle pomoću operatora new, možete koristiti novonastali objekt svagdje gdje je dopušteno koristiti objekte iz klase MotorVehicle, jer automobili jesu motorna vozila. Slično, Motorcycle možete koristiti svagdje gdje možete koristiti MotorVehicle. Ovakva uporaba objekata iz podklasa na mjestima gdje je dozvoljeno koristiti objekte iz nadklase je početak onoga što zovemo polimorfizam.

Obrat ne vrijedi jer, iako su svi automobili motorna vozila, nije istina da su sva motorna vozila automobili. Neka od njih su, na primjer, motocikli. .Dakle, ako metoda očekuje objekt klase Car, ne biste joj na tom mjestu trebali dati objekt klase MotorVehicle.

Primijetite da nismo decidirano rekli da ne smijete staviti MotorVehicle tamo gdje se očekuje Car, nego samo da ne biste trebali. Objekti se mogu pretvarati (casting) u tipove iz podklase. To je korisno pri uporabi struktura podataka kao što je, npr. Vector koji radi jedino sa generičkim objektima. Na programeru je da vodi računa o tome koji tip objekata je spremio u Vector i da ga u skladu s tim koristi.

Ispravan izbor klasa i podklasa je vještina koja se stječe iskustvom. Uvijek postoje razni načini da se klase definiraju.


Kaskadno nasljeđivanje

Nema razloga da lanac nasljeđivanja ne nastavimo i dalje pa možemo definirati klasu automobila koji imaju dvoja vrata, Compact, koja je podklasa od Car i nasljeđuje sve njene karakteristike, ali i karakteristike od MotorVehicle. U klasi Compact imat ćemo dakle, numberDoors=2

 
public class Compact extends Car {
 
  // konstruktori
  public Compact(String licensePlate, double maxSpeed,
   String make, String model, int year, int numberOfPassengers) {
    this(licensePlate, 0.0, maxSpeed, make, model, year, numberOfPassengers);    
  }
 
  public Compact(String licensePlate, double speed, double maxSpeed,
   String make, String model, int year, int numberOfPassengers) {
    super(licensePlate, speed, maxSpeed, make, model,
     year, numberOfPassengers, 2);
  }
   
}
 

U Javi, za razliku od C++ nema višestrukog nasljeđivanja. Svaka klasa može imati najviše jednu direktnu nadklasu. Situacije u kojima bi se pojavila potreba za višestrukim nasljeđivanjem u Javi se rješavaju na specifičan način, pomoću takozvanih sučelja (interfaces).


Statičke varijable i metode

Atribut ili metoda u Jav programu može biti deklarirana kao static. To znači da pripada klasi, a ne pojedinačnom objektu. Kad neki objekt iz klase promijeni vrijednost statičke varijable, onda se ta vrijednost promijenila za sve objekte u promatranoj klasi.

Na primjer, pretpostavite da klasa Car class sadrži atribut speedLimit koji je postavljen na 112 kph (70 mph). To će vrijediti za sve automobile. Ako se to promijeni (npr. zakonom) za jedan automobil, promijenit će se za sve. To je tipična statička varijabla.

Metode su najčešće statičke ako ne pristupaju ili ne modificiraju ni jednu nestatičku varijablu (varijablu instance) niti ne poziva nestatičke metode u promatranoj klasi. To je uobičajeno u računskim metodama kao što je metoda za raunanju kvadratnog korijena koja samo računa korijen iz svojih argumenata i vraća vrijednost. Jedan od načina prepoznavanja da metoda treba biti statička je ako ona niti koristi niti bi trebala koristiti ključnu riječ this.

Pogledajmo jednu varijantu klase Car koja sadrži statičku varijablu speedLimit i statičku metodu getSpeedLimit().

 
class Car {
 
  private String licensePlate; // npr. "New York 543 A23"
  private double speed;        // u kilometrima na sat
  private double maxSpeed;     // u kilometrima na sat
  private static double speedLimit = 112.0;  // kilometara na sat
  
  public Car() {
    this.licensePlate = ""; 
    this.speed  = 0.0;
    this.maxSpeed = 120.0;
  }
 
  public 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;
    
  }
 
  public 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
  
  public static double getSpeedLimit() {
    return speedLimit;
  }
 
  public boolean isSpeeding() {
    return this.speed > speedLimit;
  }
 
  public String getLicensePlate() {
    return this.licensePlate;
  }
 
  public double getMaxSpeed() {
    return this.maxSpeed;
  }
 
  public double getSpeed() {
    return this.speed;
  }
 
  // setter metoda za atribut licensePlate
  public void setLicensePlate(String licensePlate) {
    this.licensePlate = licensePlate;
  }
 
  // setter metoda za atribut maxSpeed
  public void setMaximumSpeed(double maxSpeed) {
    if (maxSpeed > 0) this.maxSpeed = maxSpeed;
    else this.maxSpeed = 0.0;
  }
 
  public void floorIt() { // ubrzanje do maksimalne brzine
    speed = maxSpeed;  
  }
  
  public 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; 
     }     
     
  }
  
}

Pozivanje statičkih metoda

Statičkim atributima ili metodama pristupa se pomoću imena odgovarajuće klase, a ne pojedinog objekta (instance) klase. Tako umjesto:

 
  Car c = new Car("New York", 89.7); 
  double maximumLegalSpeed = c.getSpeedLimit();
 

pišemo:

 
  double maximumLegalSpeed = Car.getSpeedLimit();
 

Da bi se pozvala statička metoda unutar neke klase nije čak potrebno ni postojanje nekog objekta te klase.

Statičke metode ne mogu direktno pozivati nestatičke metode ni membere iste klase. Umjesto toga, one moraju specificirati kojoj instanci klase (objektu) se obraćaju. Pokušaj pozivanja nestatičke metode ili varijable je česta pogreška koja se otkriva pri kompilaciji. Na primjer:

  public static double getSpeedLimit() {

    speed=55.0;

    return speedLimit;

  }

 
Car.java:38: non-static variable speed cannot be referenced from a static context
    speed=55.0;
    ^
%

Ključna riječ final

Ključna riječ final koristi se u različitim kontekstima označavajući da se ono na što se odnosi ne može mijenjati u nekom smislu.

Finalne klase

Primijetit ćete da su neke klase iz Java biblioteke klasa označene kao final, npr:

 
public final class String 
 

To znači da klasa ne može imati nikakvih podklasa i time se informira kompajler da može napraviti određene optimizacije koje inače ne bi mogao. To također ima nekih dobrih strana u odnosu na sigurnost i tzv. threadove (konkurentne programske tokove).

Finalne metode

Metode također mogu biti deklarirane kao final. Finalna metoda ne može biti prekrivena (overriden) u podklasi. Npr.

 
public final String convertCurrency()

Finalni atributi

Atributi mogu biti final. To nije isto kao u slučaju metoda ili klasa. Finalni atributi su zapravo konstante i oni se kad su jednom postavljeni (npr. u konstruktoru), ne mogu više mijenjati.

Atributi koji su istovremeno javni, finalni i statički su prave konstante i u Javi se tako i zovu. Npr. u nekom fizikalnom programu definirali bismo tako brzinu svjetlosti:

public class Physics {
 
  public static final double c = 2.998E8;
  
}

Finalni argumenti

Konačno, argument neke metode može biti final. To znači da ga metoda neće direktno mijenjati. Kako se u Javi argumenti ionako prenose samo po vrijednosti (a ne po lokaciji), to nije potrebno naglašavati, no ponekad može biti od pomoći.


Prekrivanje metoda (overriding)

Pretpostavimo da se, nakon što je klasa Car dovršena i koristi se u raznim programima, ukaže potreba za isto takvom klasom u kojoj će maksimalna brzina biti ograničena na 70 mph (112.65 kph).

Prva reakcija bi bila prepraviti klasu Car uvođenjem ograničenja za sve automobile, no to bi dovelo do problema u svim programima koji je već koriste jer oni pretpostavljaju da takvog ograničenja nema.