1. Alle Klassen erbenObject

Alle Klassen in Java erben implizit die ObjectKlasse.

Wir werden in der Java Core-Quest analysieren, was Vererbung ist und wie sie in Java funktioniert. Zunächst betrachten wir eine einfache Tatsache, die sich daraus ergibt:

Einer Variablen kann ein Objekt einer beliebigen Klasse zugewiesen werden Object. Beispiel:

Code Notiz
Object o = new Scanner(System.in);
Die oVariable speichert einen Verweis auf ein ScannerObjekt
Object o = new String();
Die oVariable speichert einen Verweis auf ein StringObjekt
Object o = new Integer(15);
Die oVariable speichert einen Verweis auf ein IntegerObjekt
Object o = "Hello";
Die oVariable speichert einen Verweis auf ein StringObjekt

Hier endet die gute Nachricht. Der Compiler verfolgt den ursprünglichen Typ des in einer ObjectVariablen gespeicherten Objekts nicht, sodass Sie keine anderen Methoden als die Methoden der Klasse für das gespeicherte Objekt aufrufen können .Object

Wenn Sie die mit dem ursprünglichen Typ des Objekts verknüpften Methoden aufrufen müssen, müssen Sie zunächst einen Verweis darauf in einer Variablen des richtigen Typs speichern und dann die Methoden für diese Variable aufrufen:

Code Notiz
Object o = new Scanner(System.in);
int x = o.nextInt();
Das Programm lässt sich nicht kompilieren. Die ObjectKlasse hat keine nextInt()Methode.
Object o = new Scanner(System.in);

Scanner console = (Scanner) o;

int x = console.nextInt();
Das wird funktionieren.

Hier speichern wir mithilfe eines TypumwandlungsoperatorsScanner einen Verweis auf ein Objekt in einer Variablen . Scanner

ObjectSie können einer Scannervariablen nicht einfach eine Variable zuweisen , selbst wenn die ObjectVariable einen Verweis auf ein ScannerObjekt speichert. Sie können dies jedoch tun, wenn Sie den Typecast-Operator verwenden , den Sie bereits kennen. Dies ist sein allgemeines Erscheinungsbild:

Type name1 = (Type) name2;

Dabei name1ist der Name einer TypeVariablen und name2der Name einer ObjectVariablen, die einen Verweis auf ein TypeObjekt speichert.

Typisierung

Wenn der Typ der Variablen und der Typ des Objekts nicht übereinstimmen, ClassCastExceptionwird ein Fehler ausgelöst. Beispiel:

Code Notiz
Object o = new Integer(5);
String s = (String) o;
Zur Laufzeit tritt ein Fehler auf: Hier wird
ein Fehler ausgelöstClassCastException

In Java gibt es eine Möglichkeit, diesen Fehler zu vermeiden: Wir überprüfen dazu den Typ des in einer Variablen gespeicherten Objekts :

name instanceof Type

Der instanceofOperator prüft, ob die nameVariable ein Objekt ist Type.

Lassen Sie uns als Beispiel eine Zeichenfolge in einem Array verschiedener Objekte finden:

Code Notiz
Object[] objects = {10, "Hello", 3.14};

for (int i = 0; i < objects.length; i++)
{
   if (objects[i] instanceof String)
   {
      String s = (String) objects[i];
      System.out.println(s);
   }
}
Durch Autoboxing werden diese Werte jeweils in Integer, Stringund umgewandelt Double.

Schleife über das Array von Objekten.

Wenn es sich bei dem Objekt um ein Objekt handelt, String

speichern Sie es in einer StringVariablen
. Zeigen Sie die Variable auf dem Bildschirm an.


2. Warum Generika auftauchten – Sammlungen

Kehren wir zu den Sammlungen zurück.

Sobald Java-Entwickler die ArrayListKlasse erstellt hatten, wollten sie sie universell machen, damit sie jede Art von Objekt speichern kann. Also verwendeten sie ein Array von Objects, um die Elemente zu speichern.

Die Stärke dieses Ansatzes besteht darin, dass Sie der Sammlung ein Objekt beliebigen Typs hinzufügen können.

Natürlich gibt es mehrere Schwächen.

Nachteil 1.

Beim Abrufen von Elementen aus einer Sammlung war es immer notwendig, einen Typkonvertierungsoperator zu schreiben:

Code Notiz
ArrayList numbers = new ArrayList();


for (int i = 0; i < 10; i++)
   numbers.add(i * 10);


int sum = 0;
for (int i = 0; i < 10; i++)
{
   sum = sum + (Integer) numbers.get(i);
}
Erstellen Sie eine Sammlung, um Verweise auf ObjectObjekte zu speichern

. Füllen Sie die Sammlung mit Zahlen 10, 20, ... 100;



Summieren Sie die Elemente der Sammlung.


Typecasting ist erforderlich

Nachteil 2.

Es gab keine Garantie dafür, dass eine Sammlung einen bestimmten Elementtyp enthält

Code Notiz
ArrayList numbers = new ArrayList();


for (int i = 0; i < 10; i++)
   numbers.add(i * 2.5);


int sum = 0;
for (int i = 0; i < 10; i++)
{
   sum = sum + (Integer) numbers.get(i);
}
Erstellen Sie eine Sammlung, um Verweise auf ObjectObjekte zu speichern.

Wir füllen die Sammlung mit Zahlen, die als DoubleObjekte dargestellt werden:
0.0, 2.5, 5.0, ...


Summieren Sie die Elemente der Sammlung


. Es wird ein Fehler angezeigt: a Doublekann nicht in an umgewandelt werdenInteger

Daten können überall in die Sammlung aufgenommen werden:

  • in einer anderen Methode
  • in einem anderen Programm
  • aus einer Datei
  • über das Netzwerk

Nachteil 3.

Die Daten in der Sammlung können versehentlich geändert werden.

Sie können eine mit Ihren Daten gefüllte Sammlung an eine Methode übergeben. Diese von einem anderen Programmierer geschriebene Methode fügt ihre Daten Ihrer Sammlung hinzu.

Aus dem Namen der Sammlung geht nicht eindeutig hervor, welche Datentypen darin gespeichert werden können. Und selbst wenn Sie Ihrer Variablen einen eindeutigen Namen geben, kann ein Verweis darauf an ein Dutzend Methoden übergeben werden, und diese Methoden wissen definitiv nichts über den ursprünglichen Namen der Variablen.


3. Generika

Generika in Java

In Java werden all diese Probleme durch diese coole Sache namens Generics beseitigt.

In Java bedeutet Generics die Möglichkeit, Typparameter zu Typen hinzuzufügen. Das Ergebnis ist ein komplexer zusammengesetzter Typ. Die allgemeine Ansicht eines solchen zusammengesetzten Typs ist folgende:

ClassName<TypeParameter>

Dies ist eine generische Klasse. Und es kann überall dort eingesetzt werden, wo Sie normalerweise Klassen verwenden.

Code Beschreibung
ArrayList<Integer> list;
Variablen erstellen
list = new ArrayList<Integer> ();
Objekte erstellen
ArrayList<Integer>[] array;
Arrays erstellen

IntegerIn einer solchen Sammlung können nur Variablen gespeichert werden:

Code Beschreibung
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(new Integer(1));
list.add(2);
list.add("Hello");
ArrayListSammlung mit IntegerElementen
Das ist erlaubt
Und das wird auch funktionieren
Autoboxen

Dies ist jedoch nicht zulässig: Kompilierungsfehler

In der Quest „Java-Sammlungen“ erfahren Sie, wie Sie Ihre eigenen Klassen mit Typparametern erstellen. Zunächst schauen wir uns an, wie man sie verwendet und wie sie funktionieren.


4. Wie Generika funktionieren

Eigentlich sind Generika furchtbar primitiv.

Der Compiler ersetzt einfach generische Typen durch gewöhnliche Typen. Wenn jedoch Methoden eines generischen Typs verwendet werden, fügt der Compiler einen Typecast-Operator hinzu, um Parameter in die Typparameter umzuwandeln:

Code Was der Compiler macht
ArrayList<Integer> list = new ArrayList<Integer>();
ArrayList list = new ArrayList();
list.add(1);
list.add( (Integer) 1 );
int x = list.get(0);
int x = (Integer) list.get(0);
list.set(0, 10);
list.set(0, (Integer) 10);

Angenommen, wir haben eine Methode, die die Zahlen in einer Sammlung von ganzen Zahlen summiert:

Code Was der Compiler macht
public int sum(ArrayList<Integer> numbers)
{
   int result = 0;

   for (int i = 0; i < numbers.size(); i++)
      result = result + numbers.get(i);

   return result;
}
public int sum(ArrayList numbers)
{
   int result = 0;

   for (int i = 0; i < numbers.size(); i++)
      result = result + (Integer) numbers.get(i);

   return result;
}

Mit anderen Worten, Generika sind eine Art syntaktischer Zucker, genau wie Autoboxing, aber noch ein bisschen mehr. Beim Autoboxing fügt der Compiler Methoden zum Konvertieren von an intin an Integerund umgekehrt hinzu, und für Generika fügt er Typumwandlungsoperatoren hinzu.

Nachdem der Compiler Ihre generischen Klassen mit Typparametern kompiliert hat, werden sie einfach in gewöhnliche Klassen und Typumwandlungsoperatoren konvertiert. Informationen über die Typargumente, die an Variablen generischer Typen übergeben werden, gehen verloren. Dieser Effekt wird auch als Typlöschung bezeichnet .

Manchmal benötigen Programmierer, die generische Klassen (Klassen mit Typparametern) schreiben, wirklich Informationen über die als Argumente übergebenen Typen. In der Quest „Java-Sammlungen“ erfahren Sie, wie Sie damit umgehen und was es mit sich bringt.



5. Ein paar Fakten über Generika

Hier sind einige weitere interessante Fakten über Generika.

Klassen können mehrere Typparameter haben. Es sieht ungefähr so ​​aus:

ClassName<TypeParameter1, TypeParameter2, TypeParameter3>

Eigentlich ist das nicht wirklich überraschend. Überall dort, wo der Compiler einen Operator zur Umwandlung in einen Typ hinzufügen kann, kann er mehrere Typumwandlungsoperatoren hinzufügen.

Beispiele:

Code Notiz
HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put(7, "Hello");
map.put(-15, "Hello");
Der puterste Parameter der Methode ist ein Integerund der zweite ist einString

Als Parameter können auch generische Typen verwendet werden . Es sieht ungefähr so ​​aus:

ClassName<TypeParameter<TypeParameterParameter>>

Angenommen, wir möchten eine Liste erstellen, die Listen mit Zeichenfolgen speichert. In diesem Fall erhalten wir etwa Folgendes:

// List of greetings
ArrayList<String> listHello = new ArrayList<String>();
listHello.add ("Hello");
listHello.add ("Hi");

// List of goodbyes
ArrayList<String> listBye = new ArrayList<String>();
listBye.add("Bye");
listBye.add ("Goodbye");

// List of lists
ArrayList<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
lists.add(listHello);
lists.add(listBye);

Generische Typen (Typen mit Typparametern) können auch als Array-Typen verwendet werden. Es sieht ungefähr so ​​aus:

ClassName<TypeParameter>[] array = new ClassName<TypeParameter>[size];

Hier passiert nichts Magisches: Die spitzen Klammern geben lediglich den Typnamen an:

Code Nicht-generisches Gegenstück
ArrayList<String>[] list = new ArrayList<String>[10];
StringArrayList[] list = new StringArrayList[10];
ArrayList<Integer>[] list = new ArrayList<Integer>[10];
IntegerArrayList[] list = new IntegerArrayList[10];
ArrayList<Scanner>[] list = new ArrayList<Scanner>[10];
ScannerArrayList[] list = new ScannerArrayList[10];