Suche…


Einführung

Diese Dokumentationsseite ist für Details mit Beispiel über Java - Klasse zeigt , Konstrukteure und über Objektklassenmethoden , die von dem übergeordneten Klasse automatisch vererbt werden Object einer neu erstellten Klasse.

Syntax

  • öffentliche endgültige native Klasse <?> getClass ()
  • public final native void notify ()
  • public final native void notifyAll ()
  • public final native void wait (lange Zeitüberschreitung) löst InterruptedException aus
  • public final void wait () löst InterruptedException aus
  • public final void wait (lange Zeitüberschreitung, int nanos) löst InterruptedException aus
  • public native int hashCode ()
  • public boolean equals (Object obj)
  • public String toString ()
  • protected native Object clone () löst CloneNotSupportedException aus
  • protected void finalize () wirft Throwable

toString () -Methode

Die toString() -Methode wird verwendet, um eine String Darstellung eines Objekts mithilfe des Objektinhalts zu erstellen. Diese Methode sollte beim Schreiben Ihrer Klasse überschrieben werden. toString() wird implizit aufgerufen, wenn ein Objekt wie in "hello " + anObject zu einer Zeichenfolge "hello " + anObject .

Folgendes berücksichtigen:

public class User {
    private String firstName;
    private String lastName;
    
    public User(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
    
    @Override
    public String toString() {
        return firstName + " " + lastName;
    }
    
    public static void main(String[] args) {
        User user = new User("John", "Doe");
        System.out.println(user.toString()); // Prints "John Doe"
    }   
}

Hier wird toString() aus der Object Klasse in der User Klasse überschrieben, um beim Drucken aussagekräftige Daten zum Objekt bereitzustellen.

Bei Verwendung von println() wird die toString() Methode des Objekts implizit aufgerufen. Deshalb machen diese Aussagen dasselbe:

System.out.println(user); // toString() is implicitly called on `user`
System.out.println(user.toString());

Wenn toString() in der oben genannten User Klasse nicht überschrieben wird, kann System.out.println(user) User@659e0bfd oder einen ähnlichen String mit fast keinen nützlichen Informationen außer dem Klassennamen zurückgeben. Dies wird sein , weil der Anruf wird die Verwendung toString() Implementierung der Basis Java Object - Klasse , die nichts über die weiße User der Klasse oder Geschäftsregeln. Wenn Sie diese Funktionalität in Ihrer Klasse ändern möchten, überschreiben Sie einfach die Methode.

Methode equals ()

TL; DR

== testet auf Referenzgleichheit (ob es sich um dasselbe Objekt handelt )

.equals() prüft auf .equals() ob sie logisch "gleich" sind )


equals() ist eine Methode, mit der zwei Objekte auf Gleichheit verglichen werden. Die Standardimplementierung der equals() -Methode in der Object Klasse gibt true zurück true wenn beide Referenzen auf dieselbe Instanz zeigen. Es verhält sich daher wie beim Vergleich durch == .

public class Foo {
    int field1, field2;
    String field3;

    public Foo(int i, int j, String k) {
        field1 = i;
        field2 = j;
        field3 = k;
    }

    public static void main(String[] args) {
        Foo foo1 = new Foo(0, 0, "bar");
        Foo foo2 = new Foo(0, 0, "bar");

        System.out.println(foo1.equals(foo2)); // prints false
    }
}

Obwohl foo1 und foo2 mit denselben Feldern erstellt werden, zeigen sie auf zwei verschiedene Objekte im Speicher. Die standardmäßige equals() -Implementierung wird daher zu false ausgewertet.

Um den Inhalt eines Objekts auf Gleichheit zu vergleichen, muss equals() überschrieben werden.

public class Foo {
    int field1, field2;
    String field3;

    public Foo(int i, int j, String k) {
        field1 = i;
        field2 = j;
        field3 = k;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }

        Foo f = (Foo) obj;
        return field1 == f.field1 &&
               field2 == f.field2 &&
               (field3 == null ? f.field3 == null : field3.equals(f.field3));
    }

    @Override
    public int hashCode() {
        int hash = 1;
        hash = 31 * hash + this.field1;
        hash = 31 * hash + this.field2;
        hash = 31 * hash + (field3 == null ? 0 : field3.hashCode());
        return hash;
    }

    public static void main(String[] args) {
        Foo foo1 = new Foo(0, 0, "bar");
        Foo foo2 = new Foo(0, 0, "bar");

        System.out.println(foo1.equals(foo2)); // prints true
    }
}

Hier entscheidet die überschriebene equals() -Methode, dass die Objekte gleich sind, wenn ihre Felder gleich sind.

Beachten Sie, dass die hashCode() -Methode ebenfalls überschrieben wurde. Der Vertrag für diese Methode besagt, dass, wenn zwei Objekte gleich sind, auch ihre Hash-Werte gleich sein müssen. Deshalb muss man fast immer hashCode() und equals() gemeinsam überschreiben.

Achten Sie besonders auf den Argumenttyp der Methode equals . Es ist Object obj , nicht Foo obj . Wenn Sie letzteres in Ihre Methode einfügen, ist dies keine Überschreibung der equals Methode.

Beim Schreiben Ihrer eigenen Klasse müssen Sie eine ähnliche Logik schreiben, wenn Sie equals() und hashCode() überschreiben. Die meisten IDEs können dies automatisch für Sie generieren.

Ein Beispiel für eine equals() -Implementierung finden Sie in der String Klasse, die Teil der Core-Java-API ist. Anstatt Zeiger zu vergleichen, vergleicht die String Klasse den Inhalt des String .

Java SE 7

In Java 1.7 wurde die Klasse java.util.Objects eingeführt, die eine bequeme Methode, equals , zur Verfügung stellt, die zwei potenziell null vergleicht, sodass Implementierungen der equals Methode vereinfacht werden können.

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null || getClass() != obj.getClass()) {
        return false;
    }

    Foo f = (Foo) obj;
    return field1 == f.field1 && field2 == f.field2 && Objects.equals(field3, f.field3);
}

Klassenvergleich

Da die equals-Methode für jedes Objekt ausgeführt werden kann, besteht eine der ersten Aufgaben, die die Methode (nach Überprüfung auf null ) häufig macht, darin, zu prüfen, ob die Klasse des zu vergleichenden Objekts mit der aktuellen Klasse übereinstimmt.

@Override
public boolean equals(Object obj) {
    //...check for null
    if (getClass() != obj.getClass()) {
        return false;
    }
    //...compare fields
}

Dies erfolgt normalerweise wie oben durch Vergleich der Klassenobjekte. Dies kann jedoch in einigen speziellen Fällen fehlschlagen, die möglicherweise nicht offensichtlich sind. Beispielsweise generieren einige Frameworks dynamische Proxys von Klassen, und diese dynamischen Proxies sind tatsächlich eine andere Klasse. Hier ist ein Beispiel mit JPA.

Foo detachedInstance = ...
Foo mergedInstance = entityManager.merge(detachedInstance);
if (mergedInstance.equals(detachedInstance)) {
    //Can never get here if equality is tested with getClass()
    //as mergedInstance is a proxy (subclass) of Foo
}

Ein Mechanismus, um diese Einschränkung zu umgehen, ist das Vergleichen von Klassen mithilfe von instanceof

@Override
public final boolean equals(Object obj) {
    if (!(obj instanceof Foo)) {
        return false;
    }
    //...compare fields
}

Es gibt jedoch einige Fallstricke, die bei der Verwendung von instanceof vermieden werden müssen. Da Foo möglicherweise andere Unterklassen haben könnte und diese Unterklassen möglicherweise equals() überschreiben, könnten Sie in einen Fall geraten, in dem ein Foo einer FooSubclass , die FooSubclass jedoch nicht Foo .

Foo foo = new Foo(7);
FooSubclass fooSubclass = new FooSubclass(7, false);
foo.equals(fooSubclass) //true
fooSubclass.equals(foo) //false

Dies verstößt gegen die Eigenschaften von Symmetrie und Transitivität und ist daher eine ungültige Implementierung der equals() -Methode. Daher ist es bei der Verwendung von instanceof eine gute Praxis, die equals() -Methode als final (wie im obigen Beispiel). Dadurch wird sichergestellt, dass keine Unterklasse equals() überschreibt und gegen wichtige Annahmen verstößt.

hashCode () Methode

Wenn eine Java-Klasse die Methode equals überschreibt, sollte sie auch die Methode hashCode überschreiben. Wie im Vertrag der Methode definiert:

  • Wenn die hashCode Methode während des Ausführens einer Java-Anwendung mehr als einmal für dasselbe Objekt aufgerufen wird, muss sie die gleiche ganze Zahl zurückgeben, vorausgesetzt, es werden keine Informationen geändert, die in Gleichheitsvergleichen für das Objekt verwendet werden. Diese Ganzzahl muss von einer Ausführung einer Anwendung zu einer anderen Ausführung derselben Anwendung nicht konsistent bleiben.
  • Wenn zwei Objekte gemäß der equals(Object) -Methode gleich sind, muss das Aufrufen der hashCode Methode für jedes der beiden Objekte dasselbe Integer-Ergebnis erzeugen.
  • Wenn zwei Objekte gemäß der equals(Object) -Methode ungleich sind, ist es nicht erforderlich, dass beim Aufruf der hashCode Methode für jedes der beiden Objekte unterschiedliche Integer-Ergebnisse erzeugt werden müssen. Dem Programmierer sollte jedoch bewusst sein, dass die Erzeugung eindeutiger ganzzahliger Ergebnisse für ungleiche Objekte die Leistung von Hashtabellen verbessern kann.

Hash-Codes werden in Hash-Implementierungen wie HashMap , HashTable und HashSet . Das Ergebnis der hashCode Funktion bestimmt den Bucket, in den ein Objekt hashCode wird. Diese Hash-Implementierungen sind effizienter, wenn die bereitgestellte Hash- hashCode Implementierung gut ist. Eine wichtige Eigenschaft einer guten hashCode Implementierung besteht darin, dass die Verteilung der hashCode Werte einheitlich ist. Mit anderen Worten, es besteht eine geringe Wahrscheinlichkeit, dass zahlreiche Instanzen im selben Bucket gespeichert werden.

Ein Algorithmus zum Berechnen eines Hash-Code-Werts kann dem folgenden ähnlich sein:

public class Foo {
    private int field1, field2;
    private String field3;

    public Foo(int field1, int field2, String field3) {
        this.field1 = field1;
        this.field2 = field2;
        this.field3 = field3;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }

        Foo f = (Foo) obj;
        return field1 == f.field1 &&
               field2 == f.field2 &&
               (field3 == null ? f.field3 == null : field3.equals(f.field3);
    }

    @Override
    public int hashCode() {
        int hash = 1;
        hash = 31 * hash + field1;
        hash = 31 * hash + field2;
        hash = 31 * hash + (field3 == null ? 0 : field3.hashCode());
        return hash;
    }
}

Verwenden von Arrays.hashCode () als Abkürzung

Java SE 1.2

In Java 1.2 und höher kann anstelle eines Algorithmus zur Berechnung eines Hash-Codes ein Algorithmus mit java.util.Arrays#hashCode generiert werden, indem ein Object- oder Primitives-Array mit den Feldwerten java.util.Arrays#hashCode wird:

@Override
public int hashCode() {
    return Arrays.hashCode(new Object[] {field1, field2, field3});
}
Java SE 7

Java 1.7 hat die Klasse java.util.Objects eingeführt, die eine bequeme Methode, hash(Object... objects) , bereitstellt, die einen Hash-Code basierend auf den Werten der ihm bereitgestellten Objekte berechnet. Diese Methode funktioniert genauso wie java.util.Arrays#hashCode .

@Override
public int hashCode() {
    return Objects.hash(field1, field2, field3);
}

Hinweis: Dieser Ansatz ist ineffizient und erzeugt bei jedem Aufruf Ihrer benutzerdefinierten hashCode() Methode hashCode() :

  • Ein temporäres Object[] wird erstellt. (In der Objects.hash() -Version wird das Array durch den "varargs" -Mechanismus erstellt.)
  • Wenn es sich bei den Feldern um primitive Typen handelt, müssen sie mit einem Box versehen werden, wodurch möglicherweise mehr temporäre Objekte erstellt werden.
  • Das Array muss gefüllt sein.
  • Das Array muss von der Methode Arrays.hashCode oder Objects.hash werden.
  • Die Aufrufe von Object.hashCode() , die Arrays.hashCode oder Objects.hash (wahrscheinlich) machen muss, können nicht eingebettet werden.

Internes Caching von Hash-Codes

Da die Berechnung des Hash-Codes eines Objekts teuer sein kann, kann es attraktiv sein, den Hash-Code-Wert in dem Objekt zu speichern, wenn er zum ersten Mal berechnet wird. Zum Beispiel

public final class ImmutableArray {
    private int[] array;
    private volatile int hash = 0;

    public ImmutableArray(int[] initial) {
        array = initial.clone();
    }

    // Other methods

    @Override
    public boolean equals(Object obj) {
         // ...
    }

    @Override
    public int hashCode() {
        int h = hash;
        if (h == 0) {
            h = Arrays.hashCode(array);
            hash = h;
        }
        return h;
    }
}

Bei diesem Ansatz werden die Kosten für die (wiederholte) Berechnung des Hash-Codes gegen den Overhead eines zusätzlichen Felds abgewickelt, um den Hash-Code zwischenzuspeichern. Ob sich dies als Leistungsoptimierung auszahlt, hängt davon ab, wie oft ein bestimmtes Objekt gehasht (nachgeschlagen) wird, und von anderen Faktoren.

Sie werden auch feststellen, dass der Cache unwirksam ist, wenn der echte Hashcode eines ImmutableArray gleich Null ist (eine Chance in 2 32 ).

Schließlich ist es schwieriger, diesen Ansatz korrekt zu implementieren, wenn das zu hashende Objekt veränderbar ist. Es gibt jedoch größere Bedenken, wenn sich Hash-Codes ändern. siehe den Vertrag oben.

wait () und notify () Methoden

wait() und notify() arbeiten in Tandem - wenn ein Thread Anrufe wait() auf ein Objekt, wird dieser Thread blockiert , bis ein anderer Thread ruft notify() oder notifyAll() auf demselben Objekt.

(Siehe auch: wait () / notify () )

package com.example.examples.object;

import java.util.concurrent.atomic.AtomicBoolean;

public class WaitAndNotify {

    public static void main(String[] args) throws InterruptedException {
        final Object obj = new Object();
        AtomicBoolean aHasFinishedWaiting = new AtomicBoolean(false);
    
        Thread threadA = new Thread("Thread A") {
            public void run() {
                System.out.println("A1: Could print before or after B1");
                System.out.println("A2: Thread A is about to start waiting...");
                try {
                    synchronized (obj) { // wait() must be in a synchronized block
                        // execution of thread A stops until obj.notify() is called
                        obj.wait();
                    }
                    System.out.println("A3: Thread A has finished waiting. "
                            + "Guaranteed to happen after B3");
                } catch (InterruptedException e) {
                    System.out.println("Thread A was interrupted while waiting");
                } finally {
                    aHasFinishedWaiting.set(true);
                }
            }
        };
    
        Thread threadB = new Thread("Thread B") {
            public void run() {
                System.out.println("B1: Could print before or after A1");

                System.out.println("B2: Thread B is about to wait for 10 seconds");
                for (int i = 0; i < 10; i++) {
                    try {                        
                        Thread.sleep(1000); // sleep for 1 second 
                    } catch (InterruptedException e) {
                        System.err.println("Thread B was interrupted from waiting");
                    }
                }
            
                System.out.println("B3: Will ALWAYS print before A3 since "
                        + "A3 can only happen after obj.notify() is called.");
            
                while (!aHasFinishedWaiting.get()) {
                    synchronized (obj) {
                        // notify ONE thread which has called obj.wait()
                        obj.notify();
                    }
                }
            }
        };
    
        threadA.start();
        threadB.start();
    
        threadA.join();
        threadB.join();
    
        System.out.println("Finished!");
    }
}

Einige Beispielausgabe:

A1: Could print before or after B1
B1: Could print before or after A1
A2: Thread A is about to start waiting...
B2: Thread B is about to wait for 10 seconds
B3: Will ALWAYS print before A3 since A3 can only happen after obj.notify() is called.
A3: Thread A has finished waiting. Guaranteed to happen after B3
Finished!

B1: Could print before or after A1
B2: Thread B is about to wait for 10 seconds
A1: Could print before or after B1
A2: Thread A is about to start waiting...
B3: Will ALWAYS print before A3 since A3 can only happen after obj.notify() is called.
A3: Thread A has finished waiting. Guaranteed to happen after B3
Finished!

A1: Could print before or after B1
A2: Thread A is about to start waiting...
B1: Could print before or after A1
B2: Thread B is about to wait for 10 seconds
B3: Will ALWAYS print before A3 since A3 can only happen after obj.notify() is called.
A3: Thread A has finished waiting. Guaranteed to happen after B3
Finished!

getClass () -Methode

Mit der getClass() -Methode kann der Laufzeitklassentyp eines Objekts ermittelt werden. Siehe das Beispiel unten:

public class User {
   
    private long userID;
    private String name;

    public User(long userID, String name) {
        this.userID = userID;
        this.name = name;
    }
}

public class SpecificUser extends User {
    private String specificUserID;

    public SpecificUser(String specificUserID, long userID, String name) {
        super(userID, name);
        this.specificUserID = specificUserID;
    }
}

public static void main(String[] args){
    User user = new User(879745, "John");
    SpecificUser specificUser = new SpecificUser("1AAAA", 877777, "Jim");
    User anotherSpecificUser = new SpecificUser("1BBBB", 812345, "Jenny");

    System.out.println(user.getClass()); //Prints "class User"
    System.out.println(specificUser.getClass()); //Prints "class SpecificUser"
    System.out.println(anotherSpecificUser.getClass()); //Prints "class SpecificUser"
}

Die getClass() -Methode gibt den spezifischsten Klassentyp zurück. Wenn getClass() für einen anotherSpecificUser , ist der Rückgabewert die class SpecificUser da dies die Vererbungsstruktur niedriger als User .


Es ist bemerkenswert, dass die getClass Methode zwar wie folgt deklariert ist:

public final native Class<?> getClass();

Der tatsächliche statische Typ, der von einem Aufruf an getClass ist Class<? extends T> wobei T der statische Typ des Objekts ist, für das getClass aufgerufen wird.

dh Folgendes wird kompiliert:

Class<? extends String> cls = "".getClass();

klon () methode

Die clone() -Methode wird verwendet, um eine Kopie eines Objekts zu erstellen und zurückzugeben. Diese Methode sollte vermieden werden, da sie problematisch ist und ein Kopierkonstruktor oder eine andere Methode zum Kopieren zu Gunsten von clone() .

Damit die Methode verwendet werden kann, müssen alle Klassen, die die Methode aufrufen, die Schnittstelle Cloneable implementieren.

Die Cloneable Schnittstelle selbst ist nur ein Tag - Interface verwendet , um das Verhalten der ändern native clone() Methode , die prüft , ob die anrufende Objekte Klasse implementiert Cloneable . Wenn der Aufrufer diese Schnittstelle nicht implementiert, wird eine CloneNotSupportedException ausgelöst.

Die Object Klasse selbst implementiert diese Schnittstelle nicht, so dass eine CloneNotSupportedException wird, wenn das aufrufende Objekt die Klasse Object .

Damit ein Klon korrekt ist, muss er unabhängig von dem Objekt sein, aus dem geklont wird. Daher muss das Objekt möglicherweise geändert werden, bevor es zurückgegeben wird. Dies bedeutet, dass im Wesentlichen eine "tiefe Kopie" erstellt wird, indem auch eines der veränderlichen Objekte kopiert wird, aus denen die interne Struktur des geklonten Objekts besteht. Wenn dies nicht korrekt implementiert ist, ist das geklonte Objekt nicht unabhängig und hat dieselben Verweise auf die veränderlichen Objekte wie das Objekt, aus dem es geklont wurde. Dies würde zu einem inkonsistenten Verhalten führen, da Änderungen an denen in der einen die andere beeinflussen würden.

class Foo implements Cloneable {
    int w;
    String x;
    float[] y;
    Date z;
    
    public Foo clone() {
        try {
            Foo result = new Foo();
            // copy primitives by value
            result.w = this.w;
            // immutable objects like String can be copied by reference
            result.x = this.x;
            
            // The fields y and z refer to a mutable objects; clone them recursively.
            if (this.y != null) {
              result.y = this.y.clone();
            }
            if (this.z != null) {
              result.z = this.z.clone();
            }
            
            // Done, return the new object
            return result;
            
        } catch (CloneNotSupportedException e) {
            // in case any of the cloned mutable fields do not implement Cloneable
            throw new AssertionError(e);
        }
    }
}

finalize () -Methode

Dies ist eine geschützte und nicht statische Methode der Object Klasse. Diese Methode wird verwendet, um einige abschließende Vorgänge auszuführen oder ein Objekt zu bereinigen, bevor es aus dem Speicher entfernt wird.

Laut dem Dokument wird diese Methode vom Garbage Collector für ein Objekt aufgerufen, wenn die Garbage Collection feststellt, dass keine weiteren Verweise auf das Objekt vorhanden sind.

Es gibt jedoch keine Garantie dafür, dass die finalize() -Methode aufgerufen wird, wenn das Objekt noch erreichbar ist oder kein Garbage Collectors ausgeführt wird, wenn das Objekt in Frage kommt. Deshalb ist es besser, sich nicht auf diese Methode zu verlassen.

In Java-Kernbibliotheken konnten einige Verwendungsbeispiele gefunden werden, zum Beispiel in FileInputStream.java :

protected void finalize() throws IOException {
    if ((fd != null) &&  (fd != FileDescriptor.in)) {
        /* if fd is shared, the references in FileDescriptor
         * will ensure that finalizer is only called when
         * safe to do so. All references using the fd have
         * become unreachable. We can call close()
         */
        close();
    }
}

In diesem Fall ist dies die letzte Chance, die Ressource zu schließen, wenn diese Ressource zuvor noch nicht geschlossen wurde.

Im Allgemeinen wird die Verwendung der Methode finalize() in Anwendungen jeglicher Art als schlechte Praxis betrachtet und sollte vermieden werden.

Finalizer sind nicht zum Freigeben von Ressourcen (z. B. zum Schließen von Dateien) gedacht. Der Garbage-Collector wird aufgerufen, wenn (wenn!) Das System über wenig Speicherplatz verfügt. Sie können sich nicht darauf verlassen, dass es aufgerufen wird, wenn das System nicht genügend Dateizugriffsnummern hat oder aus anderen Gründen.

Der vorgesehene Anwendungsfall für Finalizer ist, dass ein Objekt, das gerade zurückgefordert wird, ein anderes Objekt über den bevorstehenden Untergang informiert. Zu diesem Zweck gibt es jetzt einen besseren Mechanismus - die Klasse java.lang.ref.WeakReference<T> . Wenn Sie der Meinung sind, dass Sie eine finalize() Methode schreiben müssen, sollten Sie prüfen, ob Sie dasselbe Problem stattdessen mit WeakReference lösen können. Wenn sich das Problem dadurch nicht lösen lässt, müssen Sie möglicherweise Ihr Design auf einer tieferen Ebene überdenken.

Zur weiteren Lektüre hier ein Artikel über die Methode finalize() aus dem Buch "Effective Java" von Joshua Bloch.

Objektkonstruktor

Alle Konstruktoren in Java müssen den Object aufrufen. Dies geschieht mit dem Aufruf super() . Dies muss die erste Zeile eines Konstruktors sein. Der Grund dafür ist, dass das Objekt tatsächlich auf dem Heap erstellt werden kann, bevor eine weitere Initialisierung durchgeführt wird.

Wenn Sie den Aufruf von super() in einem Konstruktor nicht angeben, wird der Compiler ihn für Sie einfügen.

Alle drei Beispiele sind also funktional identisch

mit explizitem Aufruf an super() Konstruktor

public class MyClass {

    public MyClass() {
        super();
    }
}

mit implizitem Aufruf an super() Konstruktor

public class MyClass {

    public MyClass() {
        // empty
    }
}

mit implizitem Konstruktor

public class MyClass {

}

Was ist mit Konstruktor-Verkettung?

Es ist möglich, andere Konstruktoren als erste Anweisung eines Konstruktors aufzurufen. Da sowohl der explizite Aufruf eines Superkonstruktors als auch der Aufruf eines anderen Konstruktors beide erste Anweisungen sein müssen, schließen sie sich gegenseitig aus.

public class MyClass {

    public MyClass(int size) {

        doSomethingWith(size);

    }

    public MyClass(Collection<?> initialValues) {

        this(initialValues.size());
        addInitialValues(initialValues);
    }
}

Beim Aufruf von new MyClass(Arrays.asList("a", "b", "c")) wird der zweite Konstruktor mit dem List-Argument aufgerufen, das wiederum an den ersten Konstruktor delegiert wird (der implizit an super() delegiert. super() ) und rufen dann addInitialValues(int size) mit der zweiten Größe der Liste auf. Dies wird verwendet, um die Code-Duplizierung zu reduzieren, wenn mehrere Konstruktoren dieselbe Arbeit ausführen müssen.

Wie rufe ich einen bestimmten Konstruktor an?

Im obigen Beispiel kann man entweder new MyClass("argument") oder new MyClass("argument", 0) aufrufen. Mit anderen Worten, ähnlich wie beim Überladen von Methoden rufen Sie einfach den Konstruktor mit den Parametern auf, die für den ausgewählten Konstruktor erforderlich sind.

Was passiert im Objektklassenkonstruktor?

In einer Unterklasse mit einem leeren Standardkonstruktor (außer dem Aufruf von super() ) passiert nichts weiter.

Der leere Standardkonstruktor kann explizit definiert werden. Andernfalls wird er vom Compiler eingefügt, sofern noch keine anderen Konstruktoren definiert sind.

Wie wird dann ein Objekt aus dem Konstruktor in Object erstellt?

Die eigentliche Erstellung von Objekten liegt in der JVM. Jeder Konstruktor in Java erscheint als spezielle Methode mit dem Namen <init> die für die Initialisierung verantwortlich ist. Diese <init> -Methode wird vom Compiler bereitgestellt. Da <init> in Java kein gültiger Bezeichner ist, kann sie nicht direkt in der Sprache verwendet werden.

Wie ruft die JVM diese <init> -Methode auf?

Die JVM invokespecial Methode <init> mit der Anweisung invokespecial und kann nur für nicht initialisierte Klasseninstanzen aufgerufen werden.

Weitere Informationen finden Sie in der JVM-Spezifikation und der Java-Sprachspezifikation:



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow