Java'da nesne oluşturmanın tüm farklı yolları nelerdir?


178

Geçen gün bu konuda bir iş arkadaşınızla konuştum.

Bir kurucu kullanmanın aşikar olduğu var, ama orada başka yollar var mı?


2
Şüphe duyduğunuzda, dil spesifikasyonuna bakın. 12.5 Yeni Sınıf Örnekleri Oluşturma java.sun.com/docs/books/jls/third_edition/html/… 15.9 Sınıf Örneği Oluşturma İfadeleri java.sun.com/docs/books/jls/third_edition/html/…
İnternet Arkadaşı

9
yalnızca 3 tane vardır: normal c-tor (yeni anahtar kelime), klon () ve Unsafe.allocateInstance(Class). Gerisi bunlardan birini çağırıyor. Yansıma c-tor çağrısı, Unsafe.allocateInstance (Sınıf) 'a seriden kaldırma için derlenir. Kendi API'nizi oluşturabilir ve sonunda bunlardan birini arayabilirsiniz.
bestsss

2
@ bestsss- Java'nın Unsafeuygulamaya özel bir detayıdır ve spesifikasyonda hiçbir yerde belirtilmemiştir. Kodun that use için derleme yansıma aşağı kullanmayan bir uyumlu Java uygulaması oluşturmak için tamamen mümkün olduğunu new, cloneya da Unsafe.allocateInstance.
templatetypedef


Yanıtlar:


288

Java'da nesne oluşturmanın dört farklı yolu vardır:

Bir . newAnahtar kelime kullanma Java'da
bir nesne oluşturmanın en yaygın yoludur. Nesnelerin neredeyse% 99'u bu şekilde oluşturulur.

 MyObject object = new MyObject();

B . Kullanma Class.forName()
Sınıfın adını biliyorsanız ve ortak bir varsayılan yapıcısı varsa, bu şekilde bir nesne oluşturabiliriz.

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

C . Kullanılması clone()
klon () varolan nesnenin bir kopyasını oluşturmak için kullanılabilir.

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

D . object deserialization
Nesne serileştirmeyi kullanmak , serileştirilmiş formundan bir nesne oluşturmaktan başka bir şey değildir.

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

Sen onları okuyabilir burada .


10
Yani aslında sadece 2 yol vardır: kurucu çağırma (new, clone () veya yansıma kullanarak) ve kurucu çağırmayan deserialization.
AlexR

13
@AlexR: yapıcıyı da çağırmaz Object.clone().
axtavt

1
Bu en tepedeki yanıt gibi göründüğü gibi, dizilerin yaratımlarını A ve B'ye alt vaka olarak ekleyebilir misiniz? (Ayrıntılar için cevabıma bakın).
Paŭlo Ebermann

Deserializasyon, en türetilmiş türde değil, bir kurucu çağırır.
Tom Hawtin - taktik

2
ConstructorGenelleştiren sınıftan da bahsetmelisiniz Class.newInstance.
templatetypedef

68

Çeşitli yollar vardır:

  • İçinden Class.newInstance.
  • İçinden Constructor.newInstance.
  • Diziselleştirme yoluyla (en türetilmiş serileştirilemeyen temel sınıfın argüman yapıcısını kullanmaz).
  • Aracılığıyla Object.clone( yapıcı çağırmaz ).
  • JNI aracılığıyla (bir yapıcı çağırmalısınız).
  • newSizi çağıran başka bir yöntemle .
  • Sınıf yüklemesini yeni nesneler (interned gibi) oluşturmak olarak tanımlayabilirsiniz String.
  • Bir deklarasyonda başlatmanın bir parçası olarak değişmez bir dizi (diziler için yapıcı yok).
  • "Varargs" ( ...) yöntem çağrısındaki dizi (diziler için yapıcı yok).
  • Derleme dışı zaman sabiti dize birleştirme (tipik bir uygulamada en az dört nesne üretir).
  • Çalışma zamanı tarafından oluşturulacak ve atılacak bir istisna oluşuyor. Örneğin throw null;veya "".toCharArray()[0].
  • Oh, ve ilkellerin boksu (önbelleğe alınmadıkça) elbette.
  • JDK8'de dolaylı olarak nesnelere dönüştürülen lambdas (esasen özlü anonim iç sınıflar) olmalıdır.
  • Tamlık (ve Paŭlo Ebermann) için, newanahtar kelimeyle de bazı sözdizimi vardır .

6
Siz de "normal yolu"
eklemelisiniz

@ Paŭlo Ebermann Bu çok eski bir okul ve soğuk. (Sorunun ne anlama geldiğini varsaydım "bir yapıcı kullanın (her ne kadar yukarıdakilerin çoğu olmasa da, / a
yapıcıyı

aslında bunun için sadece 3 gerçek yol var, bunun için yorum ekledim
bestsss

3
Birini cevapsız: java.misc.Unsafe.allocateInstance(). Rağmen bu bir dizi nedenden dolayı kötü. Ve aslında, serileştirme argüman yapıcı kullanmaz. Kaputun altında allocateInstanceveya eşdeğer kara büyü kullanıyor.
Stephen C

En iyi cevap henüz, ama JNI AllocObject().bir yapıcı çağırmaz.
Lorne Marquis

25

Java dilinde, bir nesne oluşturmanın tek yolu, açık veya dolaylı olarak yapıcısını çağırmaktır. Yansıma kullanmak yapıcı yöntemine bir çağrı ile sonuçlanır, serileştirme yapıcıyı çağırmak için yansımayı kullanır, fabrika yöntemleri gerçek yapıyı soyutlamak için yapıcıya yapılan çağrıyı sarar ve klonlama da benzer bir yapıcı çağrısıdır.


1
Yanlış. Deserializatio, bir sınıfın yapıcısını açık veya dolaylı olarak çağırmaz.
Lorne Marquis

2
'Yapıcısını' ve 'yapıcıyı' yazmamalıyım, daha ziyade 'yapıcıyı' ve 'yapıcıyı' yazmalıydım. Deserialization durumunda, ilk uygulanabilir no-arg yapıcısı her zaman çağrılır.
Karışıklık

1
Varsayılan klon uygulaması herhangi bir kurucu çağırmaz.
Didier L

bu benim klon yöntemi uygulaması "return super.clone ();". O zaman yapıcı çağırmaz.
Mateen

13

Evet, yansıma kullanarak nesneler oluşturabilirsiniz. Örneğin, String.class.newInstance()size yeni bir boş String nesnesi verir.


1
Eğer bunu kullanırsanız onun bir try / catch bloğu içine almak istiyorum.
GuruKulki

2
Evet, istisnaların atılabileceği birçok durum vardır. Neyin yanlış gidebileceğine ilişkin örnekler için newInstance () için JavaDoc'a bakın.
Thomas Lötzer

11

Java'da nesne oluşturmanın beş farklı yolu vardır,

1. newAnahtar kelimeyi kullanarak → yapıcı çağrılır

Employee emp1 = new Employee();

2.newInstance()Class → yapıcı yöntemini kullanarak çağırmak

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

Ayrıca şu şekilde de yazılabilir:

Employee emp2 = Employee.class.newInstance();

3.newInstance()Constructor → yapıcı get yöntemini kullanarak çağrı

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

4. clone()yöntemi kullanarak → hiçbir yapıcı çağrı

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

5. Serileştirmeyi kullanma → kurucu çağrısı yok

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

İlk üç yöntem newanahtar sözcüğü ve her ikisi de newInstance()bir yapıcı çağrısı içerir, ancak daha sonra iki klon ve serileştirme yöntemi yapıcıyı çağırmadan nesneler oluşturur.

Yukarıdaki tüm yöntemlerin kendileriyle ilişkili farklı bayt kodları vardır, Örnekler için Java ile nesne oluşturmanın farklı yolları ve örnekler için daha ayrıntılı açıklamalar, örneğin tüm bu yöntemlerin bayt kodu dönüşümü.

Bununla birlikte, bir dizi veya dize nesnesi oluşturmanın da nesneyi yaratmanın bir yolu olduğu iddia edilebilir, ancak bu şeyler sadece bazı sınıflara daha spesifiktir ve doğrudan JVM tarafından işlenirken, bu 5 yolu kullanarak herhangi bir sınıfın nesnesini oluşturabiliriz.


Lütfen herhangi bir bağlantıyı açıklayın ve siteyi yayınlama yoluyla sitenizi tanıtmanın bir yolu olarak kullanmayın. Bkz. İyi bir cevabı nasıl yazarım? .
Yvette



6

Java'da yeniyseniz, her nesne Object'ten devralınmışsa bu fark edilmelidir.

korumalı yerel Nesne klonu () CloneNotSupportedException atar;


@stacker: Bunun yeni bir nesne yaratmakla nasıl bir ilgisi olduğunu açıklar mısınız? Teşekkürler.
ryanprayogo

4
@ryanprayogo clone () yeni bir nesne döndürür (nesne, clone () öğesinin çağrıldığı nesnenin bir klonu olsa da) ve aslında yapıcı çağrılmadan yeni bir nesne oluşturmanın tek yoludur.
Thomas Lötzer

6

Ayrıca, bir nesnede verilerin serileştirmesini kaldırabilirsiniz . Bu yapıcı sınıftan geçmez!


GÜNCELLENDİ : Yorumunda belirttiğin için teşekkürler Tom! Michael da denedi.

En türetilmiş serileştirilemeyen süper sınıfın yapıcısından geçer.
Ve bu sınıf hiçbir argüman yapıcısı olmadığında, serileştirme sonrasında bir InvalidClassException oluşturulur.

Lütfen tüm vakaların tam bir tedavisi için Tom'un cevabına bakın ;-) , java'da
"new" anahtar kelimesini kullanmadan nesne oluşturmanın başka bir yolu var mı?


1
Bir kurucudan (en türetilmiş serileştirilemeyen üst sınıfın arg-yapıcısı) geçer.
Tom Hawtin - tackline

1
@ Tom Oh vay - Bunu bilmiyordum ve biraz denedim. Görünüşe göre, en türetilmiş serileştirilemeyen üst sınıf bir bağımsız değişken yapıcı yoksa, bir InvalidClassException akışında serileştirilir ve serileştirme üzerine atılır !! - Bu ne kadar tuhaf?
Michael Borgwardt

6

Normal örnek oluşturma mekanizmaları (çağrı yapıcılar) tarafından oluşturulamayan bir nesne türü vardır: Diziler . Diziler aşağıdakilerle oluşturulur:

 A[] array = new A[len];

veya

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

Sean'ın bir yorumda söylediği gibi, sözdizimsel olarak bir yapıcı çağrısına benzer ve dahili olarak, bir bellek bloğunun tahsisi ve sıfırdan başlatılmasından (veya ikinci içerikte açık içerikle başlatılmasından) çok fazla değildir. tipi ve uzunluğu.

Bir varargs yöntemine argümanlar iletilirken, bir dizi de dolaylı olarak oluşturulur (ve doldurulur).

Dördüncü bir yol

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

Tabii ki, klonlama ve serileştirme de burada çalışıyor.

Standart API'de diziler oluşturan birçok yöntem vardır, ancak bunların hepsi aslında bu yollardan birini (veya daha fazlasını) kullanır.


Verilen, Dizi yapıcılarını tanımlayamazsınız, ancak bunun dışında mekanizma aynı newanahtar kelimedir. Array.newInstance buradaki tek Yeni mekanizma
Sean Patrick Floyd

@Sean: Aynı anahtar kelime, ama söylemeye cesaret edeceğim oldukça farklı bir iç mekanizma.
Paŭlo Ebermann

Tabii ki bu doğru. Ancak öte yandan dizi oluşturma işleminin farklı versiyonları dahili olarak hemen hemen aynıdır. Cevabınızın 2011'den geldiğini fark ettim. Eski şeyleri karıştırdığımız için üzgünüm :-)
Sean Patrick Floyd

@Sean: Sorun değil, bu vesileyle dilbilgisi düzeltmesi yapmak için kullandım.
Paŭlo Ebermann

iyi iş, kimse burada diziler hakkında tartışma!
Mateen

5

Kapsamlı olmamızın başka yolları.

  • Oracle JVM bir yapıcı çağırmadan bir örnek oluşturur Unsafe.allocateInstance () 'dir.
  • Kullanılması bayt kod manipülasyon size kod ekleyebilirsiniz anewarray, multianewarray, newarrayveya new. Bunlar ASM veya BCEL gibi kütüphaneler kullanılarak eklenebilir. Oracle'ın Java ile birlikte bir bcel sürümü gönderilir. Yine bu bir kurucu çağırmaz, ancak bir kurucuya ayrı bir çağrı diyebilirsiniz.


4

Yansıma sizin için de iş yapar.

SomeClass anObj = SomeClass.class.newInstance();

sınıfın yeni bir örneğini oluşturmanın başka bir yoludur. Bu durumda, atılabilecek istisnaları da ele almanız gerekir.


4
  • newoperatörü kullanmak (böylece bir kurucu çağırmak)
  • yansıma kullanarak clazz.newInstance()(yine yapıcıyı çağırır). Ya da clazz.getConstructor(..).newInstance(..)(yine bir kurucu kullanarak, ancak hangisini seçeceğinizi seçebilirsiniz)

Nesnenin sınıfının yapıcısını çağırarak cevabı - bir ana yol - özetlemek.

Güncelleme: Başka bir cevap, bir yapıcı kullanılmasını içermeyen iki yol listeledi - deseralizasyon ve klonlama.


4

Java'da nesne oluşturmanın BEŞ farklı yolu vardır:

1. "new" anahtar kelimesini kullanarak:

Java'da nesne oluşturmanın en yaygın yolu budur. Nesnelerin neredeyse% 99'u bu şekilde oluşturulur.

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

2. Fabrika Yöntemini Kullanarak:

ClassName ObgRef=ClassName.FactoryMethod();

Misal:

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

3. Klonlama Kavramını Kullanarak:

Kullanarak clone(), clone()varolan bir nesnenin bir kopyasını oluşturmak için kullanılabilir.

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

4. `Class.forName ()` kullanarak:

Sınıfın adını biliyorsak ve ortak bir varsayılan kurucuya sahipse, bu şekilde bir nesne oluşturabiliriz.

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

Misal:

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

5. Nesne serileştirmesini kullanma:

Nesnenin serileştirmesi serileştirilmiş formundan bir nesne oluşturmaktan başka bir şey değildir.

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

(4) sadece Class.forName()diğer tüm durumlarda sınıfınız yoksa gereklidir . Ayrıca argüman yapıcı gerektirmez: doğru argümanları biliyorsanız, herhangi bir genel kurucu çağırmanın yolları vardır. Ve en az iki yol daha bıraktın.
Lorne Marquis

2
(2) Fabrika Yöntemi sadece nesneleri almak için bir kalıptır. Ancak dahili olarak nesne oluşturmak için "yeni" anahtar kelimesini kullanır.
Karthik Bose

adam neden bu kadar çok insan fabrika metodunun nesneler yarattığını söylüyor, siz bunu nereden öğrendiniz?
Mateen

3

Mevcut nesneyi de klonlayabilirsiniz (Klonlanabilir ise).

Foo fooClone = fooOriginal.clone (); 

2

Yöntem 1

Yeni anahtar kelime kullanma. Java'da bir nesne oluşturmanın en yaygın yolu budur. Nesnelerin neredeyse% 99'u bu şekilde oluşturulur.

Employee object = new Employee();

Yöntem 2

Class.forName () öğesini kullanma. Class.forName () size yansıma için yararlı olan sınıf nesnesini verir. Bu nesnenin sahip olduğu yöntemler, sınıfı yazan programcı tarafından değil Java tarafından tanımlanır. Her sınıf için aynıdır. Size bu sınıfın bir örneğini veren newInstance () öğesinin çağrılması (örn. CallingClass.forName ("exampleClass"). NewInstance (), sınıfın tanımladığı yöntemleri çağırabileceğiniz yeni SampleClass () çağrılmasına eşdeğerdir, görünür alanlara vb. erişin.

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

Class.forName () her zaman arayanın ClassLoader'ını kullanır, oysa ClassLoader.loadClass () farklı bir ClassLoader belirtebilir. Class.forName yüklü sınıfı da başlatır, oysa ClassLoader.loadClass () yaklaşımı hemen yapmaz (ilk kez kullanılana kadar başlatılmaz).

Bir diğeri şöyle olmalıdır:

Java: Örnek Basit Java Enum Örneği ile İş Parçacığı Durumu Tanıtımı

Yöntem 3

Klon () kullanma. Clone () mevcut bir nesnenin bir kopyasını oluşturmak için kullanılabilir.

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

Yöntem 4

NewInstance () yöntemini kullanma

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

Yöntem 5

Nesne Diziselleştirmeyi Kullanma. Nesne Diziselleştirme, bir nesneyi serileştirilmiş formundan oluşturmaktan başka bir şey değildir.

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

Kod olmayan metinler için kod biçimlendirmesi kullanmayın. Bunlardan daha fazla yöntem var. Diğer cevapları okuyun. 'Neredeyse% 99' sadece tahmin.
Lorne Marquis

Merhaba EJP bu hata için özür dilerim ... Bu tam olarak doğru söylenmeyen nesneleri oluşturmak için bir tür yol olduğunu söyledi. Sadece bir model .. ve üzgünüm alearner ve stackoverflow için
yenisi

0

API kullanıcı perspektifinden bakıldığında, kuruculara başka bir alternatif statik fabrika yöntemleridir (BigInteger.valueOf () gibi), ancak API yazarı için (ve teknik olarak "gerçek için") nesneler yine de bir kurucu kullanılarak oluşturulur.


-1

Tam olarak oluşturmakla ne kastettiğinize bağlıdır, ancak diğer bazıları:

  • Klonlama yöntemi
  • deserialization
  • Yansıma (Class.newInstance ())
  • Yansıma (Yapıcı nesne)

2
3 ve 4, aynı mekanizma için farklı takma adlardır
Sean Patrick Floyd

-2

ClassLoader.loadClass (string) de var, ancak bu sık kullanılmıyor.

ve bu konuda tam bir avukat olmak istiyorsanız, diziler bir dizinin .length özelliği nedeniyle teknik olarak nesnelerdir. böylece bir diziyi başlatmak bir nesne oluşturur.


1
loadClass (String name), bir nesnenin oluşturduğu Class nesnesini döndürür evet Ancak bu sınıfın nesnesini döndürmez. Örnekler verilirse, java kütüphanesinde bu tür çok sayıda örnek bulabiliriz, ancak bunlar sınıfa özgü olacaktır. check youtu.be/gGGCmrD6Qpw
nanosoft

-3

Bir nesneyi 5 şekilde oluşturabiliriz:

  1. yeni operatör tarafından
  2. yansımayla (örn. Class.forName () ve ardından Class.newInstance ())
  3. fabrika yöntemi ile
  4. klonlama ile
  5. yansıma api tarafından

3
Class.forName (), nesne oluşturmak yerine bir sınıfı yükler.
Lorne Marquis

yansıma? Elbette yansıma demek istiyorsun.
Stephen C

nasıl fabrika yönteminden nesne oluşturmak istiyorsunuz, iç uygulama yine yeni anahtar kelime kullanarak olabilir değil mi? ve neden iki kez yansımanız var? Aslında bazı örnekler verirseniz daha mantıklı olur
Mateen

-5

Nesneyi şu şekilde de oluşturabiliriz: -

String s ="Hello";

Kimse tartışmadı.


Bu, ilkel veri türleri oluşturmanın bir yoludur, Java'nın perde arkasında "yeni" anahtar kelimeyi kullanmaması için sağladığı bir esnekliktir. Bu, yeni anahtar kelimeyle aynıdır.
Madusudanan

Madhusudan, FYI, Yeni operatörün yardımıyla nesneler her zaman yığın halinde saklanmalıdır, bu durumda "Merhaba" String havuzunda saklanması gereken bir nesnedir. String, ilkel bir veri türü değil bir sınıftır.
Deepak Sharma

Bu bir nesne oluşturmaz. Varolan bir nesneye başvuru atar. Nesne derleyici ve sınıf yükleyici tarafından zaten oluşturulmuştu.
Lorne Marquis
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.