Hytale Modding
Java Pamati

13 - Mantošana

Iemācies veidot klases hirearhijas un atkārtoti izmantot kodu efektīvi.

Mantošana ļauj izveidot jaunas klases balstoties uz pastāvošajām. Jaunā klase mantos visas īpašības un metodes no vecāku klases un var pievienot savas, vai modificēt mantotās.

Kas ir Mantojums?

Iedomājies to kā ģimenes koku. Bērns, kas no vecākiem mantojis īpašības, bet var arī radīt pats savas unikālās īpašības.

// Vecāku klase (superklase)
public class Entity {
    protected String name;
    protected int health;
    
    public Entity(String name, int health) {
        this.name = name;
        this.health = health;
    }
    
    public void takeDamage(int damage) {
        health -= damage;
        System.out.println(name + " zaudēja " + damage + " dzīvības!");
    }
}

// Bērna klase (subklase)
public class Player extends Entity {
    private int level;
    
    public Player(String name, int health, int level) {
        super(name, health);  // Izsauc vecāka konstruktoru
        this.level = level;
    }
    
    public void levelUp() {
        level++;
        System.out.println(name + " pacēlās uz " + level + " līmeni!");
    }
}
Mantošanas Terminoloģija
  • Superclass/Parent: Klase no kuras tiek mantots (Entity)
  • Subclass/Child: Klase, kas manto (Player)
  • extends: Atslēgvārds, lai mantotu no klases
  • super: Atslēgvārds, kas piekļūst vecāka klases locekļiem
public class Monster extends Entity {
    // Monstrs IR Entity
    // Monstrs manto no Entity
    // Entity ir vecāks, Monstrs ir bērns
}

Extends atslēgvārds

Izmanto extends mantojot no klases:

public class Animal {
    protected String name;
    
    public void makeSound() {
        System.out.println(name + " izdveš skaņu");
    }
}

public class Dog extends Animal {
    public void wagTail() {
        System.out.println(name + " kustina asti");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "Draudziņš";
        dog.makeSound();  // Manto no Animal
        dog.wagTail();    // Dog paša metode
    }
}

Super atslēgvārds

super atsaucās uz vecāku klasi:

Izsauc Vecāku Konstruktoru

public class Entity {
    protected String name;
    
    public Entity(String name) {
        this.name = name;
    }
}

public class Player extends Entity {
    private int level;
    
    public Player(String name, int level) {
        super(name);  // Izsauc vecāku konstruktoru VISPIRMS
        this.level = level;
    }
}
Konstruktora Noteikumi
  • super() jābūt pirmajam nosacījumam bērna konstruktorā
  • Ja neizsauksi super(), Java automātiski izsauks bez-argumentu vecāku konstruktoru
  • Ja vecākam nav bez-argumentu konstruktora, tev OBLIGĀTI jāizsauc super() ar argumentiem
// Nepareizi - super() nav vispirms
public Player(String name, int level) {
    this.level = level;
    super(name);  // Kļūda!
}

// Pareizi
public Player(String name, int level) {
    super(name);  // Izsaukts pirmais
    this.level = level;
}

Vecāku Metodes Izsaukšana

public class Entity {
    protected int health;
    
    public void takeDamage(int damage) {
        health -= damage;
        System.out.println("Vienība tika ievainota!");
    }
}

public class Player extends Entity {
    @Override
    public void takeDamage(int damage) {
        super.takeDamage(damage);  // Izsauc vecāku versiju
        if (health < 20) {
            System.out.println("Uzmanību: Maz Dzīvību!");
        }
    }
}

Metodes Pārrakstīšana

Bērnu klases var būt aizvietotas ar vecāku metodēm:

public class Entity {
    public void attack() {
        System.out.println("Vienība uzbrūk!");
    }
}

public class Player extends Entity {
    @Override  // Laba prakse izmantot šo anotāciju
    public void attack() {
        System.out.println("Spēlētājs vicina zobenu!");
    }
}

public class Monster extends Entity {
    @Override
    public void attack() {
        System.out.println("Monstrs iekož!");
    }
}

public class Main {
    public static void main(String[] args) {
        Player player = new Player();
        Monster monster = new Monster();
        
        player.attack();   // "Spēlētājs vicina zobenu!"
        monster.attack();  // "Monstrs iekož!"
    }
}
@Override Anotācija

Vienmēr izmanto @Override, kad pārraksti metodes:

  • Palīdz noķert drukas kļūdas (ja metode neeksistē vecākā, pretīm izmetīs kļūdu)
  • Padara kodu tīrāku
  • Laba dokumentācija
// Bez @Override - drukas kļūda netiek noķerta
public void attac() {  // Drukas kļūda! Izveidos jaunu metodi
    // ...
}

// Ar @Override - noķers kļūdu uzreiz
@Override
public void attac() {  // Kļūda: metode neeksistē vecākā
    // ...
}

Pieejas Modifikātori iekš Mantojuma

  • public - Pieejams visur
  • protected - Pieejams klasēs un apakšklasēs
  • private - Tikai klasē (netiek mantots)
public class Parent {
    public int publicVar;      // Bērns piekļūst
    protected int protectedVar; // Bērns piekļūst
    private int privateVar;     // Bērns nepiekļūst
    
    private void privateMethod() {
        // Bērns nevar izsaukt
    }
    
    protected void protectedMethod() {
        // Bērns var izsaukt
    }
}

public class Child extends Parent {
    public void test() {
        publicVar = 10;      // OK
        protectedVar = 20;   // OK
        privateVar = 30;     // Error!
        
        protectedMethod();   // OK
        privateMethod();     // Error!
    }
}

Praktiski Piemēri

Spēles Vienību Hierarhija

// Bāzes klase visām vienībām
public class Entity {
    protected String name;
    protected int health;
    protected int maxHealth;
    protected double x, y, z;
    
    public Entity(String name, int maxHealth) {
        this.name = name;
        this.health = maxHealth;
        this.maxHealth = maxHealth;
    }
    
    public void takeDamage(int damage) {
        health -= damage;
        if (health < 0) health = 0;
        System.out.println(name + " took " + damage + " damage. Health: " + health);
    }
    
    public boolean isAlive() {
        return health > 0;
    }
    
    public void moveTo(double x, double y, double z) {
        this.x = x;
        this.y = y;
        this.z = z;
        System.out.println(name + " moved to (" + x + ", " + y + ", " + z + ")");
    }
}

// Spēlētājs paplašina vienību
public class Player extends Entity {
    private int level;
    private int experience;
    private int mana;
    
    public Player(String name) {
        super(name, 100);
        this.level = 1;
        this.experience = 0;
        this.mana = 50;
    }
    
    public void gainExperience(int amount) {
        experience += amount;
        System.out.println("Gained " + amount + " XP");
        
        if (experience >= level * 100) {
            levelUp();
        }
    }
    
    private void levelUp() {
        level++;
        maxHealth += 10;
        health = maxHealth;
        mana += 5;
        System.out.println("Level up! Now level " + level);
    }
    
    @Override
    public void takeDamage(int damage) {
        super.takeDamage(damage);
        if (health < maxHealth * 0.25) {
            System.out.println("⚠ WARNING: Low health!");
        }
    }
}

// Monstrs paplašina vienību
public class Monster extends Entity {
    private int attackPower;
    private String type;
    
    public Monster(String name, int health, int attackPower, String type) {
        super(name, health);
        this.attackPower = attackPower;
        this.type = type;
    }
    
    public int attack() {
        System.out.println(name + " attacks!");
        return attackPower;
    }
    
    @Override
    public void takeDamage(int damage) {
        super.takeDamage(damage);
        if (!isAlive()) {
            System.out.println(name + " was defeated!");
        }
    }
}

// Boss paplašina Monstru (multi-līmeņu mantojums)
public class Boss extends Monster {
    private int phase;
    
    public Boss(String name, int health, int attackPower) {
        super(name, health, attackPower, "Boss");
        this.phase = 1;
    }
    
    @Override
    public void takeDamage(int damage) {
        super.takeDamage(damage);
        
        // Change phase at 50% health
        if (phase == 1 && health < maxHealth / 2) {
            phase = 2;
            System.out.println(name + " enters PHASE 2!");
        }
    }
    
    @Override
    public int attack() {
        int damage = super.attack();
        if (phase == 2) {
            damage *= 2;
            System.out.println("ENRAGED ATTACK!");
        }
        return damage;
    }
}

Priekšmetu Hirearhija

// Bāzes Priekšmeta klase
public class Item {
    protected String name;
    protected int value;
    protected double weight;
    
    public Item(String name, int value, double weight) {
        this.name = name;
        this.value = value;
        this.weight = weight;
    }
    
    public void use() {
        System.out.println("Using " + name);
    }
    
    public String getInfo() {
        return name + " ($" + value + ", " + weight + " kg)";
    }
}

// Zobeni paplašina klasi
public class Weapon extends Item {
    private int damage;
    private int durability;
    
    public Weapon(String name, int value, double weight, int damage, int durability) {
        super(name, value, weight);
        this.damage = damage;
        this.durability = durability;
    }
    
    @Override
    public void use() {
        if (durability > 0) {
            System.out.println("Attacking with " + name + " for " + damage + " damage!");
            durability--;
        } else {
            System.out.println(name + " is broken!");
        }
    }
    
    @Override
    public String getInfo() {
        return super.getInfo() + ", Damage: " + damage + ", Durability: " + durability;
    }
}

// Lietojami priekšmeti paplašina priekšmetu
public class Consumable extends Item {
    private int healAmount;
    private int uses;
    
    public Consumable(String name, int value, double weight, int healAmount, int uses) {
        super(name, value, weight);
        this.healAmount = healAmount;
        this.uses = uses;
    }
    
    @Override
    public void use() {
        if (uses > 0) {
            System.out.println("Used " + name + ", restored " + healAmount + " health!");
            uses--;
        } else {
            System.out.println("No " + name + " left!");
        }
    }
    
    @Override
    public String getInfo() {
        return super.getInfo() + ", Heals: " + healAmount + ", Uses: " + uses;
    }
}

// Bruņas paplašina priekšmetu
public class Armor extends Item {
    private int defense;
    private String slot;
    
    public Armor(String name, int value, double weight, int defense, String slot) {
        super(name, value, weight);
        this.defense = defense;
        this.slot = slot;
    }
    
    @Override
    public void use() {
        System.out.println("Equipped " + name + " (+" + defense + " defense)");
    }
    
    @Override
    public String getInfo() {
        return super.getInfo() + ", Defense: " + defense + ", Slot: " + slot;
    }
}

Polimorfisms

Bērnu objekti var būt apstrādāti kā vecāku objekti:

Entity entity1 = new Player("Alice");
Entity entity2 = new Monster("Goblin", 50, 10, "Hostile");
Entity entity3 = new Boss("Dragon", 500, 50);

// Viss var izmantot Entity metodes
entity1.takeDamage(10);
entity2.takeDamage(10);
entity3.takeDamage(10);

// Masīvs dažādiem tipiem
Entity[] entities = {
    new Player("Bob"),
    new Monster("Zombie", 30, 8, "Hostile"),
    new Monster("Spider", 20, 5, "Hostile")
};

// Apstrādā visas vienības vienādi
for (Entity entity : entities) {
    entity.takeDamage(5);
}
Polimorfisma Guvumi

Polimorfisms ļauj rakstīt kodu, kas strādā ar vecāku tipiem, bet apstrādā bērnu tipus korekti:

public void damageEntity(Entity entity, int damage) {
    entity.takeDamage(damage);
    // Darbojas priekš Spēlētāja, Monstra, Bosa u.c.
    // Katrs izmanto savu takeDamage() versiju
}

// Var izsaukt ar jebkuru vienības tipu
damageEntity(new Player("Alice"), 10);
damageEntity(new Monster("Goblin", 50, 10, "Hostile"), 10);
damageEntity(new Boss("Dragon", 500, 50), 10);

Objekta Klase

Visas klases Javā automātiski manto no Object:

public class MyClass {
    // Automātiski paplašina Object
    // Jau pieejamas metodes kā toString(), equals(), u.tml.
}

Biežākās Objektu metodes, ko pārraksta:

public class Player {
    private String name;
    private int level;
    
    @Override
    public String toString() {
        return "Player: " + name + " (Lv. " + level + ")";
    }
    
    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Player) {
            Player other = (Player) obj;
            return this.name.equals(other.name);
        }
        return false;
    }
}

Fināla Klases un Metodes

final neļauj mantot, via pārrakstīt:

// Fināla klase - nevar paplašināt
public final class SpecialItem {
    // No class can extend this
}

// Fināla metode - nevar pārrakstīt
public class Entity {
    public final void printName() {
        System.out.println(name);
    }
}

public class Player extends Entity {
    @Override
    public void printName() {  // Kļūda! Metode ir fināla
        // Nevar pārrakstīt
    }
}

Biežākās Kļūdas

// Nepareizi - Aizmirsts super()
public class Player extends Entity {
    public Player(String name) {
        // Kļūda! Vienībai nav bez-argumentu konstruktora
    }
}

// Pareizi
public class Player extends Entity {
    public Player(String name) {
        super(name, 100);  // Izsauc vecāku konstruktoru
    }
}

// Nepareizi - Piekļūst privātiem lietotājiem
public class Child extends Parent {
    public void test() {
        privateVar = 10;  // Kļūda! private nav mantots
    }
}

// Pareizi - Izmantojot protected
public class Parent {
    protected int protectedVar;  // Bērns var piekļūt
}

// Nepareizi - Vairuma Mantošana (nav atļauta Javā)
public class Child extends Parent1, Parent2 {  // Kļūda!
}

// Pareizi - Tikai viena mantošanas klase
public class Child extends Parent {
}

Prakses Vingrinājumi

  1. Transportlīdzekļu hierarhija: Izveido "Vehicle klasi ar tādām īpašībām kā ātrums un degviela. Izveido Car un Motorcycle apakšklases ar tām unikālām īpašībām.

  2. Formu kalkulators: Izveido Shape klasi ar "calculateArea()" metodi. Izveido Circle, Rectangle, un Triangle apakšklases, kas pārraksta šo metodi.

  3. Lomu Spēles Tēli: Izveido Character klasi. Paplašini to ar Warrior, Mage, un Archer klasēm, katrai ar unikālām spējām.

  4. Dzīvnieku skaņas: Izveido Animal klasi ar makeSound() metodi. Izveido vairākas dzīvnieku apakšklases, kas pārraksta šo metodi.