Eine Anleitung zum Erstellen von Objekten in Java

1. Übersicht

Einfach ausgedrückt, bevor wir mit einem Objekt in der JVM arbeiten können, muss es initialisiert werden.

In den folgenden Abschnitten werden verschiedene Möglichkeiten vorgestellt, wie primitive Typen und Objekte initialisiert werden können.

2. Erklärung vs. Initialisierung

Stellen wir zunächst sicher, dass wir uns auf derselben Seite befinden.

Bei der Deklaration wird die Variable zusammen mit ihrem Typ und Namen definiert.

Hier deklarieren wir die ID- Variable:

int id;

Bei der Initialisierung geht es dagegen darum, einen Wert zuzuweisen. zum Beispiel:

id = 1;

Zur Demonstration erstellen wir eine Benutzerklasse mit einem Namen und ID- Eigenschaften:

public class User { private String name; private int id; // standard constructor, getters, setters, }

Als nächstes werden wir sehen, dass die Initialisierung je nach Art des zu initialisierenden Feldes unterschiedlich funktioniert.

3. Objekte gegen Primitive

Java bietet zwei Arten der Datendarstellung: primitive Typen und Referenztypen. In diesem Abschnitt werden die Unterschiede zwischen den beiden in Bezug auf die Initialisierung erörtert.

Java verfügt über acht integrierte Datentypen, die als primitive Java-Typen bezeichnet werden. Variablen dieses Typs behalten ihre Werte direkt.

Referenztypen enthalten Verweise auf Objekte (Instanzen von Klassen). Im Gegensatz zu primitiven Typen, die ihre Werte in dem Speicher speichern, in dem die Variable zugewiesen ist, enthalten Referenzen nicht den Wert des Objekts, auf das sie verweisen.

Stattdessen verweist eine Referenz auf ein Objekt, indem die Speicheradresse gespeichert wird, an der sich das Objekt befindet.

Beachten Sie, dass wir mit Java die physikalische Speicheradresse nicht ermitteln können. Vielmehr können wir die Referenz nur verwenden, um auf das Objekt zu verweisen.

Schauen wir uns ein Beispiel an, das einen Referenztyp aus unserer Benutzerklasse deklariert und initialisiert :

@Test public void whenIntializedWithNew_thenInstanceIsNotNull() { User user = new User(); assertThat(user).isNotNull(); }

Wie wir hier sehen können, kann eine Referenz mit dem Schlüsselwort new, das für die Erstellung des neuen Benutzerobjekts verantwortlich ist , einer neuen zugewiesen werden.

Lassen Sie uns fortfahren und mehr über die Objekterstellung erfahren.

5. Objekte erstellen

Im Gegensatz zu Grundelementen ist die Objekterstellung etwas komplexer. Dies liegt daran, dass wir dem Feld nicht nur den Wert hinzufügen. Stattdessen lösen wir die Initialisierung mit dem neuen Schlüsselwort aus. Dies ruft im Gegenzug einen Konstruktor auf und initialisiert das Objekt im Speicher.

Lassen Sie uns die Konstruktoren und das neue Schlüsselwort genauer besprechen .

Das neue Schlüsselwort ist für die Zuweisung von Speicher für das neue Objekt über einen Konstruktor verantwortlich.

Ein Konstruktor wird normalerweise verwendet, um Instanzvariablen zu initialisieren, die die Haupteigenschaften des erstellten Objekts darstellen .

Wenn wir keinen Konstruktor explizit angeben, erstellt der Compiler einen Standardkonstruktor, der keine Argumente enthält und nur Speicher für das Objekt reserviert.

Eine Klasse kann viele Konstruktoren haben, solange ihre Parameterlisten unterschiedlich sind ( Überladung ) . Jeder Konstruktor, der keinen anderen Konstruktor in derselben Klasse aufruft, hat einen Aufruf an seinen übergeordneten Konstruktor, unabhängig davon, ob er explizit geschrieben oder vom Compiler über super () eingefügt wurde .

Fügen wir unserer Benutzerklasse einen Konstruktor hinzu :

public User(String name, int id) { this.name = name; this.id = id; }

Jetzt können wir mit unserem Konstruktor ein Benutzerobjekt mit Anfangswerten für seine Eigenschaften erstellen :

User user = new User("Alice", 1);

6. Variabler Umfang

In den folgenden Abschnitten werden wir uns die verschiedenen Arten von Bereichen ansehen, in denen eine Variable in Java vorhanden sein kann, und wie sich dies auf den Initialisierungsprozess auswirkt.

6.1. Instanz- und Klassenvariablen

Für Instanz- und Klassenvariablen müssen wir sie nicht initialisieren. Sobald wir diese Variablen deklarieren, erhalten sie einen Standardwert wie folgt:

Versuchen wir nun, einige instanz- und klassenbezogene Variablen zu definieren und zu testen, ob sie einen Standardwert haben oder nicht:

@Test public void whenValuesAreNotInitialized_thenUserNameAndIdReturnDefault() { User user = new User(); assertThat(user.getName()).isNull(); assertThat(user.getId() == 0); }

6.2. Lokale Variablen

Lokale Variablen müssen vor der Verwendung initialisiert werden , da sie keinen Standardwert haben und der Compiler nicht zulässt, dass wir einen nicht initialisierten Wert verwenden.

Der folgende Code generiert beispielsweise einen Compilerfehler:

public void print(){ int i; System.out.println(i); }

7. Das endgültige Schlüsselwort

Das letzte Schlüsselwort, das auf ein Feld angewendet wird, bedeutet, dass der Wert des Felds nach der Initialisierung nicht mehr geändert werden kann. Auf diese Weise können wir Konstanten in Java definieren.

Let's add a constant to our User class:

private static final int YEAR = 2000;

Constants must be initialized either when they're declared or in a constructor.

8. Initializers in Java

In Java, an initializer is a block of code that has no associated name or data type and is placed outside of any method, constructor, or another block of code.

Java offers two types of initializers, static and instance initializers. Let's see how we can use each of them.

8.1. Instance Initializers

We can use these to initialize instance variables.

To demonstrate, let’s provide a value for a user id using an instance initializer in our User class:

{ id = 0; }

8.2. Static Initialization Block

A static initializer or static block – is a block of code which is used to initialize static fields. In other words, it’s a simple initializer marked with the keyword static:

private static String forum; static { forum = "Java"; }

9. Order of Initialization

When writing code that initializes different types of fields, of course, we have to keep an eye on the order of initialization.

In Java, the order for initialization statements is as follows:

  • static variables and static initializers in order
  • instance variables and instance initializers in order
  • constructors

10. Object Life Cycle

Now that we've learned how to declare and initialize objects, let's discover what happens to objects when they're not in use.

Unlike other languages where we have to worry about object destruction, Java takes care of obsolete objects through its garbage collector.

All objects in Java are stored in our program's heap memory. In fact, the heap represents a large pool of unused memory, allocated for our Java application.

On the other hand, the garbage collector is a Java program that takes care of automatic memory management by deleting objects that are no longer reachable.

For a Java object to become unreachable, it has to encounter one of the following situations:

  • The object no longer has any references pointing to it
  • All reference pointing to the object are out of scope

In conclusion, an object is first created from a class, usually using the keyword new. Then the object lives its life and provides us with access to its methods and fields.

Finally, when it's no longer needed, the garbage collector destroys it.

11. Other Methods for Creating Objects

In this section, we’ll take a brief look at methods other than new keyword to create objects and how to apply them, specifically reflection, cloning, and serialization.

Reflection is a mechanism we can use to inspect classes, fields, and methods at run-time. Here's an example of creating our User object using reflection:

@Test public void whenInitializedWithReflection_thenInstanceIsNotNull() throws Exception { User user = User.class.getConstructor(String.class, int.class) .newInstance("Alice", 2); assertThat(user).isNotNull(); }

In this case, we're using reflection to find and invoke a constructor of the User class.

The next method, cloning, is a way to create an exact copy of an object. For this, our User class must implement the Cloneable interface:

public class User implements Cloneable { //... }

Jetzt können wir die clone () -Methode verwenden, um ein neues clonedUser- Objekt zu erstellen, das dieselben Eigenschaftswerte wie das Benutzerobjekt hat :

@Test public void whenCopiedWithClone_thenExactMatchIsCreated() throws CloneNotSupportedException { User user = new User("Alice", 3); User clonedUser = (User) user.clone(); assertThat(clonedUser).isEqualTo(user); }

Wir können auch die sun.misc.Unsafe- Klasse verwenden, um Speicher für ein Objekt zuzuweisen, ohne einen Konstruktor aufzurufen:

User u = (User) unsafeInstance.allocateInstance(User.class);

12. Schlussfolgerung

In diesem Tutorial haben wir die Initialisierung von Feldern in Java behandelt. Wir haben verschiedene Datentypen in Java entdeckt und wie man sie verwendet. Wir haben uns auch eingehend mit verschiedenen Möglichkeiten zum Erstellen von Objekten in Java befasst.

Die vollständige Implementierung dieses Tutorials finden Sie auf Github.