Kihagyás

9. előadás (e-Kozsik 2.)

Altípus

public class ExactTime extends Time {...}
  • ExactTime mindent tud, amit a Time
  • Amit lehet Time-mal, lehet ExactTime-mal is
  • ExactTime \(<:\) Time (ExactTime altípusa Time-nak)
  • \(\forall T\) osztályra: \(T <:\) Java.lang.Object
    • A Javában minden osztály leszármazottja a java.lang.Object osztálynak
public class Time {
    // ...
    public void aMinutePassed(){ ... }
    public boolean sameHourAs( Time that ){ ... }
}
public class ExactTime extends Time {
    // ...
    public boolean isEarlierThan( ExactTime that ){ ... }
}
ExactTime time = new ExactTime(); // 0:00:00
// Ezek a függvények léteznek, hiszen `ExactTime <: Time`
time.aMinutePassed(); // 0:01:00
time.sameHourAs( new ExactTime() ) // true

Liskov-féle helyettesítési elv (LSP) (Liskov's substitution principle)

Egy A típus altípusa a B (bázis-)típusnak \(\iff\) az A egyedeit használhatjuk a B egyedei helyett, anélkül, hogy ebből baj lenne.

Felkonvertálás

Time time = new ExactTime(); // upcast

"Azért polimorf valami, mert típussal lehet paraméterezni"

-Kozsik

Statikus típus

A változó vagy paraméter deklarált típusa

  • Programszövegből következik
  • A fordító ez alapján típusellenőriz (fordítás időben)
  • Megmondja, hogy mit lehet csinálni a változóval
Time time;

Dinamikus típus

Futási időben derül ki

Van típusrendszer lmao

time = true ? new ExactTime() : new Time();

Túlterhelés

  • Ugyanazzal a névvel, különböző szignatúrával
  • Örökölt és bevezetett műveletek
  • Fordítási időben dől el a szignatúra szerint

Felüldefiniálás (override)

  • Bázisosztályban adott műveletre
  • Ugyanazzal a névvel és paraméterezéssel
  • Ugyanaz a metódus
  • Egy példánymetódusnak lehet több implementációja
  • Futás közben választódik ki a "legspeciálisabb" implementáció

Dinamikus kötés

ExactTime e = new ExactTime();
Time t = e;
Object o = t;

System.out.println( e.toString() ); // 0:00:00
System.out.println( t.toString() ); // 0:00:00
System.out.println( o.toString() ); // 0:00:00

A legjobban illeszkedő implementáció kerül meghívásra

Statikus típusellenőrzés

Object o = new Time();
o.setHour(8); // fordítási hiba, mert az Object-nek nincs setHour metódusa

Dinamikus típusellenőrzés

Object o = new Time();
System.out.println(o.toString()); // Object-nek van toString típusa, ezért a Time által definiált toString metódust hívja le

Példa öröklődésre

package company.hr;
import java.time.ZonedDateTime;
import static java.time.temporal.ChronoUnit.YEARS;
public class Employee {
    private ZonedDateTime startDate;

    public int yearsInService(){
        return (int) startDate.until(ZonedDateTime.now(), YEARS);
    }

    private static int bonusPerYearInService = 1;

    public int bonus(){
        return yearsInService() * bonusPerYearInService;
    }
}
package company.hr;
import java.util.*;
public class Manager extends Employee {
    // megörökölt: startDate, yearsInService(), bonus, stb.

    private final HashSet<Employee> underlings = new HashSet<>();

    public void addUnderling( Employee underling ){
        underlings.add(underling);
    }

    private static int bonusPerUnderling = 1;

    @Override public int bonus(){
        return underlings.size() * bonusPerUnderling + super.bonus();
    }
}
public class Employee {
    ///...
    public int salary(){ return basicSalary + bonus(); }
}
Employee[] company = {new Employee("Jack", 1000), new Manager("Eve", 1200)};
for( Employee e: company ){
    totalSalaryCosts += e.salary(); // Az altípusnak megfelelő `salary` metódust hívja le
}

Mező és osztályszintű metódus nem definiálható felül

Például:

class Base {
    int field = 3;
    int iMethod(){ return field; }
    static int sMethod(){ return 3; }
}
class Sub extends Base {
    int field = 33; // elfedés, nem felüldefiniálás
    static int sMethod(){ return 33; } // same
}

Amiért nem felüldefiniálás, ezért:

Sub sub = new Sub();
Base base = sub;
System.out.println(sub.field);  //33
System.out.println(base.field); //3

// A Sub típusban lévő `field` az egy **teljesen más** mező, mint amit a Base-ben definiáltunk.

Konverziók referenciatípuson

Implicit konverzió

Upcast

Automatikus, altípusosság

Explicit konverzió

Downcast

Castolás (type-cast operator)

Time time = (Time)obj; // Kifejezés statikus típusa `Time`
Object obj = new Time(3, 20);
obj.aMinutePassed(); //Fordítási hiba, Object-nek nincs aMinutePassed metódusa
((Time)obj).aMinutePassed(); //Lefordul!
Object o = "Ez egy String. Ez egy String! Ez egy Striiiiing.";
o.aMinutePassed(); // Triviális fordítási hiba
((Time)o).aMinutePassed(); // Nincs fordítási hiba, de futási lesz... Köztudottan a String, az nem egy Time

instanceof

Futási időben ellenőrizhető a változó típusa/altípusa

Object o = new ExactTime(3,20,0);

if( o instanceof Time ){
    ((Time)o).aMinutePassed();
}

null esetén false

Típuskonverziók

Automatikus

byte < short < int < long long < float float < double char < int

byte b = 42;
short s = 42;
char c = 42;

Explicit típuskényszerítés (type cast)

int i = 42;
short s = (short)i;