Jakie są różne sposoby tworzenia obiektu w Javie?


178

Rozmawiałem o tym pewnego dnia ze współpracownikiem.

Używanie konstruktora jest oczywiste, ale jakie są inne sposoby?


2
W razie wątpliwości spójrz na specyfikację języka. 12.5 Tworzenie nowych wystąpień klasy java.sun.com/docs/books/jls/third_edition/html/... 15.9 Wyrażenia tworzenia wystąpień klasy java.sun.com/docs/books/jls/third_edition/html/...
Przyjaciel internetowy

9
są tylko 3: normalny c-tor (nowe słowo kluczowe), klon () i Unsafe.allocateInstance(Class). Reszta nazywa jedną z nich. Refleksja jest kompilowana do wywołania c-tor, deserializacja do Unsafe.allocateInstance (klasa). Możesz stworzyć swój własny interfejs API i ostatecznie zadzwonisz do jednego z nich.
bestsss,

2
@ bestsss- Unsafejest szczegółowym wykonaniem Javy i nie jest nigdzie wspomniany w specyfikacji. Jest całkiem możliwe zbudowanie zgodnego wdrażania Java, który nie korzysta z kompilacji odbicie w dół do kodu, który używa new, clone, lub Unsafe.allocateInstance.
templatetypedef


Odpowiedzi:


288

Istnieją cztery różne sposoby tworzenia obiektów w Javie:

. Używanie newsłowa kluczowego
Jest to najczęstszy sposób tworzenia obiektu w java. W ten sposób powstaje prawie 99% obiektów.

 MyObject object = new MyObject();

B . Korzystanie Class.forName()
Jeśli znamy nazwę klasy i jeśli ma ona publiczny domyślny konstruktor, możemy w ten sposób utworzyć obiekt.

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

C . Korzystanie z funkcji clone()
klonowania () można użyć do utworzenia kopii istniejącego obiektu.

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

D . Korzystanie z object deserialization
deserializacji obiektów jest niczym innym jak tworzeniem obiektu na podstawie postaci serializowanej.

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

Możesz je przeczytać tutaj .


10
Tak naprawdę istnieją tylko 2 sposoby: wywołanie konstruktora (przy użyciu new, clone () lub refleksji) i deserializacja, która nie wywołuje konstruktora.
AlexR

13
@AlexR: Object.clone()też nie wywołuje konstruktora.
axtavt

1
Ponieważ wydaje się, że jest to odpowiedź u góry, czy możesz dodać układy tablic jako pod-przypadki do A i B? (Szczegóły znajdują się w mojej odpowiedzi).
Paŭlo Ebermann

Deserializacja powoduje wywołanie konstruktora, po prostu nie najbardziej pochodnego typu.
Tom Hawtin - tackline

2
Powinieneś także wspomnieć o Constructorklasie, która się uogólnia Class.newInstance.
templatetypedef

68

Istnieją różne sposoby:

  • Przez Class.newInstance.
  • Przez Constructor.newInstance.
  • Poprzez deserializację (wykorzystuje konstruktor no-args z najbardziej pochodnej nieserializowalnej klasy podstawowej).
  • Poprzez Object.clone( nie wywołuje konstruktora ).
  • Poprzez JNI (powinien wywołać konstruktora).
  • Za pomocą dowolnej innej metody, która wywołuje newdla ciebie.
  • Myślę, że można opisać ładowanie klas jako tworzenie nowych obiektów (takich jak internowane String ).
  • Dosłowna tablica jako część inicjalizacji w deklaracji (brak konstruktora dla tablic).
  • Tablica w ...wywołaniu metody „varargs” ( ) (brak konstruktora dla tablic).
  • Niekompilowana konkatenacja ciągów stałych czasowych (zdarza się, że powstają co najmniej cztery obiekty, na typowej implementacji).
  • Powodowanie wyjątku, który zostanie utworzony i zgłoszony przez środowisko wykonawcze. Na przykład throw null;lub "".toCharArray()[0].
  • Aha, i boksowanie prymitywów (chyba że w pamięci podręcznej), oczywiście.
  • JDK8 powinien mieć lambdas (zasadniczo zwięzłe anonimowe klasy wewnętrzne), które są domyślnie konwertowane na obiekty.
  • Dla kompletności (i Paŭlo Ebermann) istnieje także pewna składnia ze newsłowem kluczowym.

6
Powinieneś także dodać „normalny sposób” :-)
Paŭlo Ebermann

@ Paŭlo Ebermann To taka stara szkoła i niechęć. (Założyłem, że to, co oznacza pytanie „użyj konstruktora (chociaż większość, ale nie wszystkie powyższe, używają konstruktora / a gdzieś wzdłuż linii).)
Tom Hawtin - omówiono

właściwie są tylko 3 prawdziwe sposoby, aby to zrobić, do których dodałem komentarz
bestsss

3
Przegapiłeś jednego: java.misc.Unsafe.allocateInstance(). Chociaż jest to paskudne z wielu powodów. W rzeczywistości deserializacja nie korzysta z konstruktora no-args. Pod maską używa allocateInstancelub równoważnej czarnej magii.
Stephen C

Najlepsza odpowiedź, ale JNI AllocObject().nie wywołuje konstruktora.
Markiz Lorne

25

W języku Java jedynym sposobem na utworzenie obiektu jest wywołanie jego konstruktora, jawnie lub niejawnie. Wykorzystując odbicie powoduje wywołanie metody konstruktora, deserializacja używa odbicia do wywołania konstruktora, metody fabryczne zawijają wywołanie do konstruktora w celu wyodrębnienia faktycznej konstrukcji, a klonowanie jest podobnie zapakowanym wywołaniem konstruktora.


1
Błędny. Deserializatio nie wywołuje konstruktora klasy ani jawnie, ani niejawnie.
Markiz Lorne

2
Nie powinienem był pisać „jego konstruktor” i „konstruktor”, ale „konstruktor” i „konstruktor”. W przypadku deserializacji zawsze wywoływany jest pierwszy odpowiedni konstruktor bez arg.
Zamieszanie

1
Domyślna implementacja klonowania nie wywołuje żadnego konstruktora.
Didier L,

jeśli jest to implementacja metody klonowania „return super.clone ();”. Wtedy nie wywoła konstruktora.
Mateen

13

Tak, możesz tworzyć obiekty za pomocą odbicia. Na przykład String.class.newInstance()da ci nowy pusty obiekt String.


1
jeśli go użyję, poprosi mnie o włączenie go do bloku try / catch.
GuruKulki,

2
Tak, istnieje wiele przypadków, w których można zgłaszać wyjątki. Zobacz JavaDoc dla newInstance (), aby zobaczyć przykłady tego, co może pójść nie tak.
Thomas Lötzer,

11

Istnieje pięć różnych sposobów tworzenia obiektu w Javie,

1. Za pomocą newsłowa kluczowego → wywołać konstruktora

Employee emp1 = new Employee();

2. Przy użyciu newInstance()metodyClass → konstruktora wywołaj

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

Można go również zapisać jako

Employee emp2 = Employee.class.newInstance();

3. Przy użyciu newInstance()metodyConstructor → konstruktora wywołaj

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

4. Korzystanie z clone()metody → brak wywołania konstruktora

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

5. Korzystanie z deserializacji → brak wywołania konstruktora

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

Pierwsze trzy newsłowa kluczowe metody i oba newInstance()zawierają wywołanie konstruktora, ale później dwie metody klonowania i deserializacji tworzą obiekty bez wywoływania konstruktora.

Wszystkie powyższe metody są powiązane z innym kodem bajtowym. Przeczytaj Różne sposoby tworzenia obiektów w Javie z Przykładem dla przykładów i bardziej szczegółowym opisem, np. Konwersja kodu bajtowego wszystkich tych metod.

Można jednak argumentować, że utworzenie obiektu tablicowego lub łańcuchowego jest również sposobem na utworzenie obiektu, ale te rzeczy są bardziej specyficzne tylko dla niektórych klas i obsługiwane bezpośrednio przez JVM, podczas gdy możemy stworzyć obiekt dowolnej klasy przy użyciu tych 5 sposobów.


Proszę ujawnić wszelkie powiązania i nie wykorzystywać witryny jako sposobu promowania witryny poprzez publikowanie. Zobacz Jak napisać dobrą odpowiedź? .
Yvette - Przywróć Monikę



6

Należy to zauważyć, jeśli jesteś nowy w Javie, każdy obiekt odziedziczył po Object

chroniony natywny Object clone () zgłasza CloneNotSupportedException;


@stacker: Czy możesz wyjaśnić, jak to się wiąże z tworzeniem nowego obiektu? Dzięki.
ryanprayogo

4
@ryanprayogo clone () zwróci nowy obiekt (nawet jeśli obiekt jest klonem obiektu, który został wywołany przez clone ()) i jest tak naprawdę jedynym sposobem na utworzenie nowego obiektu bez wywołania konstruktora.
Thomas Lötzer,

6

Ponadto można przekształcić dane do postaci szeregowej w obiekt. To nie przechodzi przez klasowego Konstruktora!


ZAKTUALIZOWANO : Dzięki Tom za zwrócenie na to uwagi w komentarzu! I Michael także eksperymentował.

Przechodzi przez konstruktor najbardziej pochodnej nieserializowalnej nadklasy.
A gdy ta klasa nie ma konstruktora bez argumentów, wyjątek InvalidClassException jest generowany po deserializacji.

Proszę zobaczyć odpowiedź Toma, aby uzyskać pełne traktowanie wszystkich przypadków ;-)
czy istnieje jakikolwiek inny sposób utworzenia obiektu bez użycia „nowego” słowa kluczowego w java


1
Przechodzi przez konstruktor (konstruktor bez argonu najbardziej pochodnej nadselekcji nieserializowalnej).
Tom Hawtin - tackline

1
@ Tom Oh wow - nie wiedziałem o tym i trochę eksperymentowałem. Najwyraźniej, gdy najbardziej wyprowadzona nieserializowalna nadklasa nie ma konstruktora bez argumentów, powoduje to, że InvalidClassException jest serializowany do strumienia i zgłaszany po deserializacji !! - Jakie to dziwne?
Michael Borgwardt,

6

Istnieje rodzaj obiektu, którego nie można zbudować za pomocą zwykłych mechanizmów tworzenia instancji (wywoływanie konstruktorów): Tablice . Tablice są tworzone za pomocą

 A[] array = new A[len];

lub

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

Jak powiedział Sean w komentarzu, jest to syntaktycznie podobne do wywołania konstruktora, a wewnętrznie nie jest niczym więcej niż alokacją i inicjalizacją zera (lub inicjowaniem z jawną zawartością, w drugim przypadku) blok pamięci, z nagłówkiem wskazującym typ i długość.

Podczas przekazywania argumentów do metody varargs, tablica jest tam również tworzona (i wypełniana) również w sposób niejawny.

Czwarty sposób byłby

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

Oczywiście działa tutaj również klonowanie i deserializacja.

Standardowe API zawiera wiele metod, które tworzą tablice, ale w rzeczywistości wszystkie wykorzystują jeden (lub więcej) z tych sposobów.


To prawda, że ​​nie można zdefiniować konstruktorów Array, ale poza tym mechanizm jest tym samym newsłowem kluczowym. Array.newInstance to jedyny nowy mechanizm tutaj
Sean Patrick Floyd

@Sean: To samo słowo kluczowe, ale śmiem powiedzieć, że jest to zupełnie inny mechanizm wewnętrzny.
Paŭlo Ebermann

To prawda, oczywiście. Ale z drugiej strony różne wersje tworzenia tablic są wewnętrznie prawie takie same. Właśnie zdałem sobie sprawę, że twoja odpowiedź pochodzi z 2011 roku. Przepraszamy za mieszanie starych rzeczy :-)
Sean Patrick Floyd

@Sean: Nie ma problemu, skorzystałem z okazji, aby poprawić gramatykę.
Paŭlo Ebermann

dobra robota, nikt nie dyskutował tutaj o tablicach!
Mateen

5

Inne sposoby, jeśli jesteśmy wyczerpujący.

  • Na Oracle JVM jest Unsafe.allocateInstance (), który tworzy instancję bez wywoływania konstruktora.
  • Korzystanie manipulacji kodu bajtowego można dodać kod anewarray, multianewarray, newarraylub new. Można je dodać za pomocą bibliotek takich jak ASM lub BCEL. Wersja bcel jest dostarczana z Javą Oracle. Ponownie nie wywołuje to konstruktora, ale można wywołać konstruktora jako osobne wywołanie.


4

Refleks również wykona pracę za Ciebie.

SomeClass anObj = SomeClass.class.newInstance();

jest innym sposobem na utworzenie nowej instancji klasy. W takim przypadku będziesz musiał także poradzić sobie z wyjątkami, które mogą zostać zgłoszone.


4
  • używając new operatora (w ten sposób wywołanie konstruktora)
  • za pomocą odbicia clazz.newInstance()(które ponownie wywołuje konstruktora). Lub przez clazz.getConstructor(..).newInstance(..)(ponownie używając konstruktora, ale możesz więc wybrać, który z nich)

Podsumowując odpowiedź - jednym głównym sposobem - przez wywołanie konstruktora klasy obiektu.

Aktualizacja: Inna odpowiedź wymienia dwa sposoby, które nie wymagają użycia konstruktora - dezintegrację i klonowanie.


4

Istnieje PIĘĆ różnych sposobów tworzenia obiektów w Javie:

1. Używając słowa kluczowego „new”:

Jest to najczęstszy sposób tworzenia obiektu w Javie. W ten sposób powstaje prawie 99% obiektów.

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

2. Przy użyciu metody fabrycznej:

ClassName ObgRef=ClassName.FactoryMethod();

Przykład:

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

3. Korzystając z koncepcji klonowania:

Dzięki zastosowaniu clone()The clone()mogą być wykorzystywane do tworzenia kopii istniejącego obiektu.

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

4. Używając `Class.forName ()`:

Jeśli znamy nazwę klasy i jeśli ma ona publiczny domyślny konstruktor, możemy w ten sposób utworzyć obiekt.

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

Przykład:

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

5. Korzystanie z deserializacji obiektów:

Deserializacja obiektu to nic innego jak tworzenie obiektu na podstawie postaci serializowanej.

ObjectInputStreamName inStream = new ObjectInputStreamName(anInputStream );
MyObjectName object = (MyObjectNmae) inStream.readObject();

(4) wymaga tylko, Class.forName()jeśli nie masz jeszcze klasy, co robisz we wszystkich innych przypadkach. Nie wymaga też konstruktora bez argumentów: istnieją sposoby na wywołanie dowolnego konstruktora publicznego, jeśli znasz poprawne argumenty. I pominąłeś co najmniej dwa inne sposoby.
Markiz Lorne

2
(2) Metoda fabryczna to tylko wzorzec do zdobywania przedmiotów. Ale wewnętrznie używa „nowego” słowa kluczowego do tworzenia obiektów.
Karthik Bose

człowieku, dlaczego tak wielu ludzi mówi, że metoda fabryczna tworzy obiekty, skąd się nauczyliście?
Mateen

3

Możesz także sklonować istniejący obiekt (jeśli implementuje on funkcję klonowania).

Foo fooClone = fooOriginal.clone (); 

2

Metoda 1

Używanie nowego słowa kluczowego. Jest to najczęstszy sposób tworzenia obiektu w java. W ten sposób powstaje prawie 99% obiektów.

Employee object = new Employee();

Metoda 2

Korzystanie z Class.forName (). Class.forName () daje obiekt klasy, który jest przydatny do refleksji. Metody, które ma ten obiekt, są definiowane przez Javę, a nie przez programistę piszącego klasę. Są takie same dla każdej klasy. Wywołanie newInstance () na tej instancji daje instancję tej klasy (tj. WywoływanieClass.forName („ExampleClass”). NewInstance () jest równoważne z wywoływaniem new ExampleClass ()), na której można wywoływać metody zdefiniowane przez klasę, dostęp do widocznych pól itp.

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

Class.forName () zawsze będzie używać ClassLoader wywołującego, podczas gdy ClassLoader.loadClass () może określać inny ClassLoader. Uważam, że Class.forName inicjuje również ładowaną klasę, podczas gdy podejście ClassLoader.loadClass () nie robi tego od razu (nie jest inicjowane, dopóki nie zostanie użyte po raz pierwszy).

Inny musi przeczytać:

Java: Wprowadzenie do stanu wątku z przykładem Prosty przykład enum Java

Metoda 3

Używanie clone (). Klon () może być użyty do utworzenia kopii istniejącego obiektu.

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

Metoda 4

Korzystanie z metody newInstance ()

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

Metoda 5

Korzystanie z deserializacji obiektów. Deserializacja obiektu to nic innego jak tworzenie obiektu na podstawie postaci zserializowanej.

// 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();

Nie używaj formatowania kodu dla tekstu, który nie jest kodem. Jest więcej metod niż te. Przeczytaj pozostałe odpowiedzi. „Prawie 99%” to tylko zgadywanie.
Markiz Lorne

Cześć EJP przepraszam za ten błąd ... Powiedziałem, że jest to jeden ze sposobów na stworzenie obiektów, które nie są dokładnie powiedziane. To tylko model .. przepraszam, ale alearner i nowy do stackoverflow
Andriya

0

Z punktu widzenia użytkownika API inną alternatywą dla konstruktorów są statyczne metody fabryczne (takie jak BigInteger.valueOf ()), chociaż dla autora API (i technicznie „na żywo”) obiekty są nadal tworzone przy użyciu konstruktora.


-1

Zależy dokładnie, co masz na myśli przez tworzenie, ale niektóre inne to:

  • Metoda klonowania
  • Deserializacja
  • Odbicie (Class.newInstance ())
  • Odbicie (obiekt Konstruktora)

2
3 i 4 to różne aliasy dla tego samego mechanizmu
Sean Patrick Floyd

-2

istnieje również ClassLoader.loadClass (ciąg), ale nie jest to często używane.

a jeśli chcesz być w tym całkowitym prawnikiem, tablice są technicznie obiektami ze względu na właściwość tablicy .length. więc zainicjowanie tablicy tworzy obiekt.


1
loadClass (nazwa ciągu) zwraca wynikowy obiekt klasy, który jest obiektem tak, ale nie obiekt tej klasy. Jeśli podano przykłady, możemy znaleźć wiele takich przykładów w całej bibliotece Java, ale będą one specyficzne dla klasy. sprawdzić youtu.be/gGGCmrD6Qpw
nanosoft

-3

Możemy stworzyć obiekty na 5 sposobów:

  1. przez nowego operatora
  2. przez odbicie (np. Class.forName (), a następnie Class.newInstance ())
  3. metodą fabryczną
  4. przez klonowanie
  5. przez odbicie api

3
Class.forName () ładuje klasę zamiast tworzyć obiekt.
Markiz Lorne

refleksja? Na pewno masz na myśli refleksję.
Stephen C

jak stworzyłbyś obiekt z metody fabrycznej, wewnętrzna implementacja może być znowu przy użyciu nowego słowa kluczowego, prawda? i dlaczego dwa razy się zastanawiasz? Byłoby bardziej sensowne, gdybyś rzeczywiście dał kilka przykładów
Mateen

-5

Możemy również utworzyć obiekt w ten sposób:

String s ="Hello";

Nikt o tym nie rozmawiał.


Jest to sposób tworzenia prymitywnych typów danych, to tylko elastyczność, którą Java zapewnia za kulisami, aby nie używać „nowego” słowa kluczowego. Jest to to samo, co nowe słowo kluczowe.
Madusudanan

Madhusudan, FYI, Z pomocą nowego operatora obiekty powinny zawsze przechowywać się w stercie, podczas gdy w tym przypadku „Cześć” to obiekt, który powinien być przechowywany w puli ciągów. A String to klasa nie prymitywny typ danych.
Deepak Sharma

To nie tworzy obiektu. Przypisuje odwołanie do istniejącego obiektu. Obiekt został już utworzony przez kompilator i moduł ładujący klasy.
Markiz Lorne
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.