Welche verschiedenen Möglichkeiten gibt es, ein Objekt in Java zu erstellen?

178

Hatte neulich ein Gespräch mit einem Kollegen darüber.

Es ist offensichtlich, einen Konstruktor zu verwenden, aber wie sieht es anders aus?

Mike Deck
quelle
2
Schauen Sie sich im Zweifelsfall die Sprachspezifikation an. 12.5 Erstellen neuer Klasseninstanzen java.sun.com/docs/books/jls/third_edition/html/… 15.9 Ausdrücke zum Erstellen von Klasseninstanzen java.sun.com/docs/books/jls/third_edition/html/…
Internet Friend
9
Es gibt nur 3: normaler c-tor (neues Schlüsselwort), clone () und Unsafe.allocateInstance(Class). Der Rest nennt einen von denen. Die Reflexion wird kompiliert, um den C-Tor-Aufruf und die Deserialisierung auf Unsafe.allocateInstance (Class) durchzuführen. Sie können Ihre eigene API erstellen und am Ende eine davon aufrufen.
Bests
2
@ bestsss- Unsafeist ein implementierungsspezifisches Detail von Java und wird an keiner Stelle in der Spezifikation erwähnt. Es ist durchaus möglich, eine kompatible Java-Implementierung zu erstellen, die keine Kompilierungsreflexion bis hin zu Code verwendet new, der clone,, oder verwendet Unsafe.allocateInstance.
Templatetypedef

Antworten:

288

Es gibt vier verschiedene Möglichkeiten, Objekte in Java zu erstellen:

A . Verwenden des newSchlüsselworts
Dies ist die häufigste Methode zum Erstellen eines Objekts in Java. Fast 99% der Objekte werden auf diese Weise erstellt.

 MyObject object = new MyObject();

B . Verwenden Class.forName()
Wenn wir den Namen der Klasse kennen und einen öffentlichen Standardkonstruktor haben, können wir auf diese Weise ein Objekt erstellen.

MyObject object = (MyObject) Class.forName("subin.rnd.MyObject").newInstance();

C . Verwenden von clone()
clone () kann verwendet werden, um eine Kopie eines vorhandenen Objekts zu erstellen.

MyObject anotherObject = new MyObject();
MyObject object = (MyObject) anotherObject.clone();

D . Die Verwendung der object deserialization
Objektdeserialisierung ist nichts anderes als das Erstellen eines Objekts aus seiner serialisierten Form.

ObjectInputStream inStream = new ObjectInputStream(anInputStream );
MyObject object = (MyObject) inStream.readObject();

Sie können sie hier lesen .

Kamaci
quelle
10
Es gibt also nur zwei Möglichkeiten: Aufrufen des Konstruktors (unter Verwendung von new, clone () oder Reflection) und Deserialisierung, die keinen Konstruktor aufruft.
AlexR
13
@AlexR: Ruft Object.clone()auch keinen Konstruktor auf.
Axtavt
1
Könnten Sie, da dies oben die Antwort zu sein scheint, die Kreationen von Arrays als Unterfälle zu A und B hinzufügen? (Siehe meine Antwort für Details).
Paŭlo Ebermann
Die Deserialisierung ruft einen Konstruktor auf, nur nicht vom am meisten abgeleiteten Typ.
Tom Hawtin - Tackline
2
Sie sollten auch die ConstructorKlasse erwähnen , die verallgemeinert Class.newInstance.
Templatetypedef
68

Es gibt verschiedene Möglichkeiten:

  • Durch Class.newInstance.
  • Durch Constructor.newInstance.
  • Durch Deserialisierung (verwendet den Konstruktor no-args der am meisten abgeleiteten nicht serialisierbaren Basisklasse).
  • Through Object.clone( ruft keinen Konstruktor auf ).
  • Über JNI (sollte einen Konstruktor aufrufen).
  • Durch jede andere Methode, die ein newfür Sie aufruft .
  • Ich denke, Sie könnten das Laden von Klassen als das Erstellen neuer Objekte (z. B. internierte Strings) beschreiben.
  • Ein Literal-Array als Teil der Initialisierung in einer Deklaration (kein Konstruktor für Arrays).
  • Das Array in einem Methodenaufruf "varargs" ( ...) (kein Konstruktor für Arrays).
  • Verkettung von Zeichenfolgen ohne Kompilierungszeitkonstante (erzeugt bei einer typischen Implementierung mindestens vier Objekte).
  • Eine Ausnahme wird erstellt und von der Laufzeit ausgelöst. Zum Beispiel throw null;oder "".toCharArray()[0].
  • Oh, und natürlich das Boxen von Primitiven (sofern nicht zwischengespeichert).
  • JDK8 sollte Lambdas (im Wesentlichen prägnante anonyme innere Klassen) haben, die implizit in Objekte konvertiert werden.
  • Der Vollständigkeit halber (und Paŭlo Ebermann) gibt es auch eine Syntax mit dem newSchlüsselwort.
Tom Hawtin - Tackline
quelle
6
Sie sollten auch den "normalen Weg" hinzufügen :-)
Paŭlo Ebermann
@ Paŭlo Ebermann Das ist so altmodisch und uncool. (Ich nahm an, was die Frage mit "Verwenden eines Konstruktors" bedeutete (obwohl die meisten, aber nicht alle der oben genannten den / einen Konstruktor irgendwo entlang der Linie verwenden).)
Tom Hawtin - Tackline
Eigentlich gibt es nur 3 echte Möglichkeiten, für die ich einen Kommentar hinzugefügt habe
bestsss
3
Sie haben einen verpasst : java.misc.Unsafe.allocateInstance(). Obwohl das aus einer Reihe von Gründen böse ist. Tatsächlich verwendet die Deserialisierung nicht den Konstruktor no-args. Unter der Haube verwendet es allocateInstanceoder gleichwertige schwarze Magie.
Stephen C
Beste Antwort bisher, aber JNI AllocObject().ruft keinen Konstruktor auf.
Marquis von Lorne
25

Innerhalb der Java-Sprache besteht die einzige Möglichkeit, ein Objekt zu erstellen, darin, seinen Konstruktor aufzurufen, sei es explizit oder implizit. Die Verwendung von Reflection führt zu einem Aufruf der Konstruktormethode. Bei der Deserialisierung wird Reflection zum Aufrufen des Konstruktors verwendet. Factory-Methoden umschließen den Aufruf an den Konstruktor, um die tatsächliche Konstruktion zu abstrahieren, und das Klonen ist in ähnlicher Weise ein umbrochener Konstruktoraufruf.

Verwirrtheit
quelle
1
Falsch. Deserializatio ruft den Konstruktor einer Klasse weder explizit noch implizit auf.
Marquis von Lorne
2
Ich hätte nicht "seinen Konstruktor" und "den Konstruktor" schreiben sollen, sondern "einen Konstruktor" und "einen Konstruktor". Bei der Deserialisierung wird immer der erste anwendbare No-Arg-Konstruktor aufgerufen.
Verwirrung
1
Die Standardklonimplementierung ruft keinen Konstruktor auf.
Didier L
Wenn dies meine Implementierung der Klonmethode ist, "return super.clone ();". Dann wird der Konstruktor nicht aufgerufen.
Mateen
13

Ja, Sie können Objekte mithilfe von Reflexion erstellen. Sie erhalten beispielsweise String.class.newInstance()ein neues leeres String-Objekt.

Thomas Lötzer
quelle
1
Wenn ich dies benutze, werde ich gebeten, einen Try / Catch-Block einzuschließen.
GuruKulki
2
Ja, es gibt viele Fälle, in denen Ausnahmen ausgelöst werden können. Im JavaDoc für newInstance () finden Sie Beispiele dafür, was möglicherweise schief geht.
Thomas Lötzer
11

Es gibt fünf verschiedene Möglichkeiten, ein Objekt in Java zu erstellen:

1. Mit newSchlüsselwort → Konstruktor wird aufgerufen

Employee emp1 = new Employee();

2. Mit der newInstance()MethodeClass → Konstruktor wird aufgerufen

Employee emp2 = (Employee) Class.forName("org.programming.mitra.exercises.Employee")
                                .newInstance();

Es kann auch geschrieben werden als

Employee emp2 = Employee.class.newInstance();

3. Mit der newInstance()MethodeConstructor → Konstruktor wird aufgerufen

Constructor<Employee> constructor = Employee.class.getConstructor();
Employee emp3 = constructor.newInstance();

4. Mit clone()Methode → kein Konstruktoraufruf

Employee emp4 = (Employee) emp3.clone();

5. Deserialisierung verwenden → kein Konstruktoraufruf

ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
Employee emp5 = (Employee) in.readObject();

Die ersten drei Methoden newSchlüsselwörter und beide newInstance()enthalten einen Konstruktoraufruf, aber später erstellen zwei Klon- und Deserialisierungsmethoden Objekte, ohne den Konstruktor aufzurufen.

Allen oben genannten Methoden ist ein anderer Bytecode zugeordnet. Lesen Sie verschiedene Methoden zum Erstellen von Objekten in Java mit Beispielbeispielen und einer detaillierteren Beschreibung, z. B. Bytecode-Konvertierung all dieser Methoden.

Man kann jedoch argumentieren, dass das Erstellen eines Arrays oder eines String-Objekts auch eine Möglichkeit zum Erstellen des Objekts ist. Diese Dinge sind jedoch nur für einige Klassen spezifischer und werden direkt von JVM behandelt, während wir mit diesen fünf Methoden ein Objekt jeder Klasse erstellen können.

Naresh Joshi
quelle
Bitte legen Sie jegliche Zugehörigkeit offen und verwenden Sie die Website nicht, um Ihre Website durch Veröffentlichung zu bewerben. Siehe Wie schreibe ich eine gute Antwort? .
Yvette
6

Auch können Sie verwenden

 Object myObj = Class.forName("your.cClass").newInstance();
Vincent Ramdhanie
quelle
6

Dies sollte beachtet werden, wenn Sie neu in Java sind und jedes Objekt von Object geerbt hat

protected native Object clone () löst CloneNotSupportedException aus;

Stapler
quelle
@stacker: Könnten Sie bitte erklären, wie dies mit dem Erstellen eines neuen Objekts zusammenhängt? Vielen Dank.
Ryanprayogo
4
@ryanprayogo clone () gibt ein neues Objekt zurück (obwohl das Objekt ein Klon des Objekts ist, für das clone () aufgerufen wurde) und ist tatsächlich die einzige Möglichkeit, ein neues Objekt zu erstellen, ohne dass der Konstruktor aufgerufen wird.
Thomas Lötzer
6

Sie können Daten auch in ein Objekt de-serialisieren . Dies geht nicht durch die Klasse Konstruktor!


AKTUALISIERT : Vielen Dank, Tom, dass Sie in Ihrem Kommentar darauf hingewiesen haben! Und Michael experimentierte auch.

Es geht durch den Konstruktor der am meisten abgeleiteten nicht serialisierbaren Superklasse.
Und wenn diese Klasse keinen Konstruktor ohne Argumente hat, wird bei der De-Serialisierung eine InvalidClassException ausgelöst.

In Toms Antwort finden Sie eine vollständige Behandlung aller Fälle ;-) Gibt
es eine andere Möglichkeit, ein Objekt zu erstellen, ohne das Schlüsselwort "new" in Java zu verwenden?

KLE
quelle
1
Es durchläuft einen Konstruktor (den No-Arg-Konstruktor der am meisten abgeleiteten nicht serialisierbaren Superklasse).
Tom Hawtin - Tackline
1
@ Tom Oh wow - das wusste ich nicht und experimentierte ein bisschen. Wenn die am meisten abgeleitete nicht serialisierbare Superklasse keinen Konstruktor ohne Argumente hat , führt dies anscheinend dazu, dass eine InvalidClassException in den Stream serialisiert und bei der Deserialisierung ausgelöst wird !! - Wie bizarr ist das?
Michael Borgwardt
6

Es gibt einen Objekttyp, der nicht durch normale Instanzerstellungsmechanismen (aufrufende Konstruktoren) erstellt werden kann: Arrays . Arrays werden mit erstellt

 A[] array = new A[len];

oder

 A[] array = new A[] { value0, value1, value2 };

Wie Sean in einem Kommentar sagte, ähnelt dies syntaktisch einem Konstruktoraufruf und ist intern nicht viel mehr als die Zuweisung und Nullinitialisierung (oder Initialisierung mit explizitem Inhalt, im zweiten Fall) eines Speicherblocks mit einem Header zur Angabe des Typ und Länge.

Bei der Übergabe von Argumenten an eine varargs-Methode wird dort auch implizit ein Array erstellt (und gefüllt).

Ein vierter Weg wäre

 A[] array = (A[]) Array.newInstance(A.class, len);

Natürlich funktioniert auch hier das Klonen und Deserialisieren.

Es gibt viele Methoden in der Standard-API, die Arrays erstellen, aber alle verwenden tatsächlich eine (oder mehrere) dieser Methoden.

Paŭlo Ebermann
quelle
Zugegeben, Sie können keine Array-Konstruktoren definieren, aber ansonsten ist der Mechanismus dasselbe newSchlüsselwort. Array.newInstance ist der einzige neue Mechanismus hier
Sean Patrick Floyd
@ Sean: Es ist das gleiche Schlüsselwort, aber es ist ein ganz anderer interner Mechanismus, wage ich zu sagen.
Paŭlo Ebermann
Das stimmt natürlich. Andererseits sind die verschiedenen Versionen der Array-Erstellung intern ziemlich gleich. Ich habe gerade festgestellt, dass Ihre Antwort aus dem Jahr 2011 stammt. Entschuldigen Sie, dass Sie alte Sachen aufgewühlt haben :-)
Sean Patrick Floyd
@ Sean: Kein Problem, ich habe diese Gelegenheit genutzt, um eine Grammatikkorrektur durchzuführen.
Paŭlo Ebermann
Gute Arbeit, hier wurde niemand über Arrays diskutiert!
Mateen
5

Andere Möglichkeiten, wenn wir erschöpfend sind.

  • In der Oracle-JVM befindet sich Unsafe.allocateInstance (), die eine Instanz erstellt, ohne einen Konstruktor aufzurufen.
  • Mit Byte - Code - Manipulation können Sie Code hinzufügen anewarray, multianewarray, newarrayoder new. Diese können mithilfe von Bibliotheken wie ASM oder BCEL hinzugefügt werden. Eine Version von bcel wird mit Java von Oracle geliefert. Auch dies ruft keinen Konstruktor auf, aber Sie können einen Konstruktor als separaten Aufruf aufrufen.
Peter Lawrey
quelle
4

Reflexion:

someClass.newInstance();
John Meagher
quelle
4

Reflexion erledigt auch die Arbeit für Sie.

SomeClass anObj = SomeClass.class.newInstance();

ist eine weitere Möglichkeit, eine neue Instanz einer Klasse zu erstellen. In diesem Fall müssen Sie auch die Ausnahmen behandeln, die möglicherweise ausgelöst werden.

Ryanprayogo
quelle
4
  • Verwenden des newOperators (Aufrufen eines Konstruktors)
  • Verwenden von Reflection clazz.newInstance()(wodurch der Konstruktor erneut aufgerufen wird). Oder durch clazz.getConstructor(..).newInstance(..)(wieder mit einem Konstruktor, aber Sie können so wählen, welcher)

Um die Antwort zusammenzufassen - eine Hauptmethode - durch Aufrufen des Konstruktors der Objektklasse.

Update: In einer anderen Antwort wurden zwei Möglichkeiten aufgeführt, bei denen kein Konstruktor verwendet werden muss: Deseralisierung und Klonen.

Bozho
quelle
4

Es gibt FÜNF verschiedene Möglichkeiten, Objekte in Java zu erstellen:

1. Verwenden des Schlüsselworts "new":

Dies ist die häufigste Methode zum Erstellen eines Objekts in Java. Fast 99% der Objekte werden auf diese Weise erstellt.

MyObject object = new MyObject();//normal way

2. Mit der Factory-Methode:

ClassName ObgRef=ClassName.FactoryMethod();

Beispiel:

RunTime rt=Runtime.getRunTime();//Static Factory Method

3. Mit dem Klonkonzept:

Durch die Verwendung clone(), die clone()können eine Kopie eines bestehenden Objekts erstellen verwendet werden.

MyObjectName anotherObject = new MyObjectName();
MyObjectName object = anotherObjectName.clone();//cloning Object

4. Verwenden von `Class.forName ()`:

Wenn wir den Namen der Klasse kennen und einen öffentlichen Standardkonstruktor haben, können wir auf diese Weise ein Objekt erstellen.

MyObjectName object = (MyObjectNmae) Class.forName("PackageName.ClassName").newInstance();

Beispiel:

String st=(String)Class.forName("java.lang.String").newInstance();

5. Verwenden der Objektdeserialisierung:

Objektdeserialisierung ist nichts anderes als das Erstellen eines Objekts aus seiner serialisierten Form.

ObjectInputStreamName inStream = new ObjectInputStreamName(anInputStream );
MyObjectName object = (MyObjectNmae) inStream.readObject();
KVSubrahmanya Reddy
quelle
(4) erfordert nur, Class.forName()wenn Sie die Klasse noch nicht haben, was Sie in allen anderen Fällen tun. Es ist auch kein Konstruktor ohne Argumente erforderlich: Es gibt Möglichkeiten, einen öffentlichen Konstruktor aufzurufen, wenn Sie die richtigen Argumente kennen. Und Sie haben mindestens zwei andere Möglichkeiten ausgelassen.
Marquis von Lorne
2
(2) Die Factory-Methode ist nur ein Muster zum Abrufen von Objekten. Intern wird jedoch das Schlüsselwort "new" zum Erstellen von Objekten verwendet.
Karthik Bose
Mann, warum sagen so viele Leute, dass Fabrikmethoden Objekte erstellen? Woher habt ihr das gelernt?
Mateen
3

Sie können auch ein vorhandenes Objekt klonen (sofern es Cloneable implementiert).

Foo fooClone = fooOriginal.clone (); 
römisch
quelle
2

Methode 1

Neues Schlüsselwort verwenden. Dies ist die häufigste Methode zum Erstellen eines Objekts in Java. Fast 99% der Objekte werden auf diese Weise erstellt.

Employee object = new Employee();

Methode 2

Verwenden von Class.forName (). Class.forName () gibt Ihnen das Klassenobjekt, das für die Reflexion nützlich ist. Die Methoden dieses Objekts werden von Java definiert, nicht vom Programmierer, der die Klasse schreibt. Sie sind für jede Klasse gleich. Wenn Sie newInstance () aufrufen, erhalten Sie eine Instanz dieser Klasse (dh callingClass.forName ("ExampleClass"). NewInstance () entspricht dem Aufruf von new ExampleClass ()), für die Sie die von der Klasse definierten Methoden aufrufen können. Zugriff auf die sichtbaren Felder usw.

Employee object2 = (Employee) Class.forName(NewEmployee).newInstance();

Class.forName () verwendet immer den ClassLoader des Aufrufers, während ClassLoader.loadClass () einen anderen ClassLoader angeben kann. Ich glaube, dass Class.forName auch die geladene Klasse initialisiert, während der ClassLoader.loadClass () -Ansatz dies nicht sofort tut (er wird erst initialisiert, wenn er zum ersten Mal verwendet wird).

Ein anderer muss lesen:

Java: Thread-Status Einführung mit Beispiel Einfaches Java-Enum-Beispiel

Methode 3

Verwenden von clone (). Mit clone () kann eine Kopie eines vorhandenen Objekts erstellt werden.

Employee secondObject = new Employee();
Employee object3 = (Employee) secondObject.clone();

Methode 4

Verwenden der newInstance () -Methode

Object object4 = Employee.class.getClassLoader().loadClass(NewEmployee).newInstance();

Methode 5

Verwenden der Objektdeserialisierung. Objektdeserialisierung ist nichts anderes als das Erstellen eines Objekts aus seiner serialisierten Form.

// Create Object5
// create a new file with an ObjectOutputStream
FileOutputStream out = new FileOutputStream("");
ObjectOutputStream oout = new ObjectOutputStream(out);

// write something in the file
oout.writeObject(object3);
oout.flush();

// create an ObjectInputStream for the file we created before
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("crunchify.txt"));
Employee object5 = (Employee) ois.readObject();
Andriya
quelle
Verwenden Sie keine Code-Formatierung für Text, der kein Code ist. Es gibt mehr Methoden als diese. Lesen Sie die anderen Antworten. "Fast 99%" ist nur eine Vermutung.
Marquis von Lorne
Hallo EJP Entschuldigung für diesen Fehler ... Ich sagte , dies sei eine Art von Weg , um die Objekte nicht genau gesagt das die richtigen one.Its nur model..and leider am alearner und neuen zu schaffen , um Stackoverflow
Andriya
0

Aus Sicht des API-Benutzers sind statische Factory-Methoden (wie BigInteger.valueOf ()) eine weitere Alternative zu Konstruktoren. Für den API-Autor (und technisch "real") werden die Objekte jedoch weiterhin mit einem Konstruktor erstellt.

Fabian Steeg
quelle
-1

Kommt genau darauf an, was du mit create meinst, aber einige andere sind:

  • Klonmethode
  • Deserialisierung
  • Reflexion (Class.newInstance ())
  • Reflexion (Konstruktorobjekt)
Garth Gilmour
quelle
2
3 und 4 sind verschiedene Aliase für den gleichen Mechanismus
Sean Patrick Floyd
-2

Es gibt auch ClassLoader.loadClass (Zeichenfolge), die jedoch nicht häufig verwendet wird.

und wenn Sie ein totaler Anwalt sein möchten, sind Arrays aufgrund der .length-Eigenschaft eines Arrays technisch gesehen Objekte. Wenn Sie also ein Array initialisieren, wird ein Objekt erstellt.

Randy L.
quelle
1
loadClass (String name) gibt das resultierende Klassenobjekt zurück, das ein Objekt ist. Ja, aber nicht das Objekt dieser Klasse. Wenn Beispiele angegeben werden, finden wir in der gesamten Java-Bibliothek zahlreiche solcher Beispiele, die jedoch klassenspezifisch sind. check youtu.be/gGGCmrD6Qpw
nanosoft
-3

Wir können Objekte auf 5 Arten erstellen:

  1. vom neuen Betreiber
  2. durch Reflexion (zB Class.forName () gefolgt von Class.newInstance ())
  3. nach Fabrikmethode
  4. durch Klonen
  5. durch Reflexion api
Tanushree Roy
quelle
3
Class.forName () lädt eine Klasse, anstatt ein Objekt zu erstellen.
Marquis von Lorne
Reflexion? Sicher meinst du Nachdenken.
Stephen C
Wie würden Sie ein Objekt aus der Factory-Methode erstellen? Die interne Implementierung verwendet möglicherweise wieder ein neues Schlüsselwort, oder? und warum reflektierst du zweimal? Es wäre sinnvoller, wenn Sie tatsächlich einige Beispiele geben
Mateen
-5

Wir können das Objekt auch folgendermaßen erstellen:

String s ="Hello";

Niemand hat darüber gesprochen.

Deepak Sharma
quelle
Dies ist die Art und Weise, primitive Datentypen zu erstellen. Es ist nur eine Flexibilität, die Java hinter den Kulissen bietet, um das "neue" Schlüsselwort nicht zu verwenden. Dies ist dasselbe wie das neue Schlüsselwort.
Madusudanan
Madhusudan, FYI, Mit Hilfe eines neuen Operators sollten Objekte immer im Heap gespeichert werden, während in diesem Fall "Hello" ein Objekt ist, das im String-Pool gespeichert werden soll. Und String ist eine Klasse, kein primitiver Datentyp.
Deepak Sharma
Dadurch wird kein Objekt erstellt. Es weist einem vorhandenen Objekt einen Verweis zu. Das Objekt wurde bereits vom Compiler und Classloader erstellt.
Marquis von Lorne