JavaRush /Blog Java /Random-PL /Klasy abstrakcyjne w Javie z konkretnymi przykładami

Klasy abstrakcyjne w Javie z konkretnymi przykładami

Opublikowano w grupie Random-PL
Cześć! Na poprzednich wykładach zapoznaliśmy się z interfejsami i zorientowaliśmy się, do czego są potrzebne. Dzisiejszy temat będzie miał coś wspólnego z poprzednim. Porozmawiajmy o klasach abstrakcyjnych w Javie. Klasy abstrakcyjne w Javie z konkretnymi przykładami - 1

Dlaczego klasy nazywane są „abstrakcyjnymi”

Pewnie pamiętasz, czym jest „abstrakcja” - już o tym pisaliśmy :) Jeśli nagle zapomniałeś, nie ma problemu, pamiętajmy: to zasada OOP , zgodnie z którą projektując klasy i tworząc obiekty, należy podkreślać tylko główne właściwości jednostki i odrzuć drugorzędne. Na przykład, jeśli projektujemy klasę SchoolTeacher– nauczyciela – jest mało prawdopodobne, że będziemy potrzebować cechy „ wzrostu ”. Rzeczywiście: dla nauczyciela ta cecha nie jest istotna. Ale jeśli utworzymy w programie klasę BasketballPlayer- koszykarz - wzrost stanie się jedną z głównych cech. Zatem klasa abstrakcyjna jest najbardziej abstrakcyjnym, jakże przybliżonym „pustym” miejscem dla grupy przyszłych klas. Preparatu tego nie można stosować w postaci gotowej – jest zbyt „surowy”. Opisuje jednak pewien ogólny stan i zachowanie, jakie będą miały przyszłe klasy – spadkobiercy klasy abstrakcyjnej.

Przykłady klas abstrakcyjnych Java

Spójrzmy na prosty przykład z samochodami:
public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public abstract void gas();

   public abstract void brake();

   public String getModel() {
       return model;
   }

   public void setModel(String model) {
       this.model = model;
   }

   public String getColor() {
       return color;
   }

   public void setColor(String color) {
       this.color = color;
   }

   public int getMaxSpeed() {
       return maxSpeed;
   }

   public void setMaxSpeed(int maxSpeed) {
       this.maxSpeed = maxSpeed;
   }
}
Tak wygląda najprostsza klasa abstrakcyjna. Jak widać nic specjalnego :) Do czego może nam to być potrzebne? Przede wszystkim w najbardziej abstrakcyjny sposób opisuje potrzebną nam istotę – samochód. Słowo abstrakcja pojawiło się tutaj nie bez powodu. Na świecie nie ma „tylko maszyn”. Są ciężarówki, samochody wyścigowe, sedany, coupe, SUV-y. Nasza klasa abstrakcyjna to po prostu „plan”, z którego później stworzymy klasy samochodów.
public class Sedan extends Car {

   @Override
   public void gas() {
       System.out.println(„Sedan przyspiesza!”);
   }

   @Override
   public void brake() {
       System.out.println(„Sedan zwalnia!”);
   }

}
To bardzo przypomina to, o czym mówiliśmy na wykładach na temat dziedziczenia. Tylko tam mieliśmy klasę Cari jej metody, które nie były abstrakcyjne. Jednak to rozwiązanie ma wiele wad, które są korygowane w klasach abstrakcyjnych. Przede wszystkim nie można utworzyć instancji klasy abstrakcyjnej:
public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Błąd! Klasa Car jest abstrakcyjna!
   }
}
Ta „sztuczka” została zaimplementowana specjalnie przez twórców Javy. Jeszcze raz, żeby pamiętać: klasa abstrakcyjna to tylko plan przyszłych „normalnych” klas . Nie potrzebujesz kopii rysunku, prawda? Nie ma więc potrzeby tworzenia instancji klasy abstrakcyjnej :) A gdyby klasa Carnie była abstrakcyjna, z łatwością moglibyśmy stworzyć jej obiekty:
public class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       //trochę logiki
   }

   public  void brake() {
       //trochę logiki
   }
}


public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Wszystko jest OK, maszyna została utworzona
   }
}
Teraz mamy w naszym programie jakiś dziwny samochód - nie ciężarówkę, nie samochód wyścigowy, nie sedan, ale coś w ogóle. Ta sama „tylko maszyna”, która nie istnieje w naturze. Ten sam przykład można podać ze zwierzętami. Wyobraź sobie, że w Twoim programie pojawiły się obiekty Animal– „ tylko zwierzę ”. Jaki to typ, do jakiej rodziny należy, jakie ma cechy - nie jest jasne. Dziwnie byłoby zobaczyć go w programie. W przyrodzie nie ma „tylko zwierząt”. Tylko psy, koty, lisy, krety i inne. Klasy abstrakcyjne uwalniają nas od „ tylko obiektów ”. Dają nam podstawowy stan i zachowanie. Na przykład wszystkie samochody muszą mieć model , kolor i maksymalną prędkość , a także muszą mieć możliwość gazu i hamulca . To wszystko. Jest to ogólny abstrakcyjny schemat, następnie sam projektujesz potrzebne klasy. Uwaga: dwie metody w klasie abstrakcyjnej są również oznaczone jako abstrakcyjne i w ogóle nie są zaimplementowane. Powód jest ten sam: klasy abstrakcyjne nie tworzą „domyślnego zachowania” dla „zwykłych maszyn”. Mówią tylko, że powinni być w stanie wyprodukować wszystkie samochody. Jeśli jednak nadal potrzebujesz zachowania domyślnego, możesz zaimplementować metody w klasie abstrakcyjnej. Java tego nie zabrania:
public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       System.out.println("Chodźmy!");
   }

   public abstract void brake();

   // pobierające i ustawiające
}


public class Sedan extends Car {

   @Override
   public void brake() {
       System.out.println(„Sedan zwalnia!”);
   }

}

public class Main {

   public static void main(String[] args) {

       Sedan sedan = new Sedan();
       sedan.gas();
   }
}
Dane wyjściowe konsoli: „Przyspiesz!” Jak widać, zaimplementowaliśmy jedną metodę w klasie abstrakcyjnej, ale nie zaimplementowaliśmy drugiej. W rezultacie zachowanie naszej klasy Sedanzostało podzielone na dwie części: jeśli wywołasz na niej metodę gas(), zostanie ona „wyciągnięta” z nadrzędnej klasy abstrakcyjnej Car, a brake()my na nowo zdefiniowaliśmy metodę w klasie Sedan. Okazało się to bardzo wygodne i elastyczne. Ale teraz nasza klasa nie jest już tak abstrakcyjna ? W końcu połowa jego metod jest wdrożona. W rzeczywistości – i jest to bardzo ważna cecha – klasa jest abstrakcyjna, jeśli przynajmniej jedna z jej metod jest abstrakcyjna . Przynajmniej jeden z dwóch, przynajmniej jeden z tysiąca sposobów – to nie ma znaczenia. Możemy nawet wdrożyć wszystkie metody i nie pozostawiać żadnych abstrakcyjnych. Będzie klasa abstrakcyjna bez metod abstrakcyjnych. W zasadzie jest to możliwe i kompilator nie będzie generował błędów, ale lepiej tego nie robić: słowo streszczenie straci swoje znaczenie, a Twoi koledzy programiści będą bardzo zaskoczeni, gdy to zobaczą :/ Co więcej, jeśli metoda jest oznaczona słowem abstrakcyjny, każda klasa potomna musi implementować lub zostać zadeklarowana jako abstrakcyjna. W przeciwnym razie kompilator zgłosi błąd . Oczywiście każda klasa może dziedziczyć tylko z jednej klasy abstrakcyjnej, zatem pod względem dziedziczenia nie ma różnicy pomiędzy klasami abstrakcyjnymi i zwykłymi. Nie ma znaczenia, czy dziedziczymy z klasy abstrakcyjnej, czy ze zwykłej, klasa nadrzędna może być tylko jedna.

Dlaczego w Javie nie ma dziedziczenia wielu klas?

Powiedzieliśmy już, że w Javie nie ma dziedziczenia wielokrotnego, ale tak naprawdę nie mamy pojęcia, dlaczego. Spróbujmy tego teraz. Chodzi o to, że gdyby Java miała wielokrotne dziedziczenie, klasy potomne nie byłyby w stanie zdecydować, które zachowanie wybrać. Powiedzmy, że mamy dwie klasy - Tosteri NuclearBomb:
public class Toster {


 public void on() {

       System.out.println(„Toster jest włączony, tosty się szykują!”);
   }

   public void off() {

       System.out.println("Toster jest wyłączony!");
   }
}


public class NuclearBomb {

   public void on() {

       System.out.println("Взрыв!");
   }
}
Jak widać, oba mają metodę on(). W przypadku tostera zaczyna on gotować tosty, a w przypadku bomby atomowej powoduje eksplozję. Och :/ A teraz wyobraź sobie, że postanowiłeś (nie wiem dlaczego nagle!) stworzyć coś pomiędzy. A oto twoja klasa - MysteriousDevice! Ten kod oczywiście nie działa i przedstawiamy go po prostu jako przykład „jak mogłoby być”:
public class MysteriousDevice extends Toster, NuclearBomb {

   public static void main(String[] args) {

       MysteriousDevice mysteriousDevice = new MysteriousDevice();
       mysteriousDevice.on(); // A co powinno się tu stać? Czy dostaniemy toast, czy nuklearną apokalipsę?
   }
}
Zobaczmy, co mamy. Tajemnicze urządzenie pochodzi zarówno z Tostera, jak i Bomby Nuklearnej. Obydwa mają metodę on()i w rezultacie nie jest jasne, która metoda on()powinna zostać uruchomiona na obiekcie MysteriousDevice, jeśli ją wywołamy. Obiekt nie będzie w stanie tego zrozumieć. Cóż, jak wisienka na torcie: Bomba Nuklearna nie ma metody off(), więc jeśli się pomylimy, nie będzie możliwości wyłączenia urządzenia. Klasy abstrakcyjne w Javie z konkretnymi przykładami - 2 Właśnie z powodu tego zamieszania, gdy obiekt nie jest pewien, jakie zachowanie powinien wybrać, twórcy Javy porzucili wielokrotne dziedziczenie. Pamiętasz jednak, że klasy Java implementują wiele interfejsów. Swoją drogą, na studiach spotkałeś już przynajmniej jedną klasę abstrakcyjną! Chociaż może tego nie zauważyłem :)
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
To jest twoja stara znajoma klasa Calendar. Jest abstrakcyjny i ma kilku spadkobierców. Jeden z nich jest GregorianCalendar. Używałeś go już na lekcjach o datach :) Wszystko wydaje się jasne, pozostała tylko jedna kwestia: jaka jest zasadnicza różnica pomiędzy klasami abstrakcyjnymi a interfejsami ? Dlaczego dodali oba do Javy i nie ograniczyli się do jednego? To mogłoby wystarczyć. Porozmawiamy o tym w następnym wykładzie! Do zobaczenia:)
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION