Javaでオブジェクトを作成するすべての異なる方法は何ですか?


178

先日、これについて同僚と会話しました。

コンストラクタを使用することは明らかですが、他の方法は何ですか?


2
疑問がある場合は、言語仕様を確認してください。新しいクラスインスタンスの12.5創造java.sun.com/docs/books/jls/third_edition/html/... 15.9クラスインスタンス生成式java.sun.com/docs/books/jls/third_edition/html/...
インターネットフレンド

9
通常のc-tor(新しいキーワード)、clone()およびの3つだけがありUnsafe.allocateInstance(Class)ます。残りはそれらの1つを呼び出します。リフレクションはc-tor呼び出しにコンパイルされ、Unsafe.allocateInstance(Class)に逆シリアル化されます。独自のAPIを作成すると、そのうちの1つを呼び出すことになります。
bestss

2
@ bestsss- Unsafeは、Javaの実装固有の詳細であり、仕様のどこにも記載されていません。使用しているコードまで、コンパイルリフレクションを使用していません準拠したJavaの実装を構築することが完全に可能であるnewcloneまたはUnsafe.allocateInstance
templatetypedef

2
リンクを確認できます 。codesandlogics.com
2017/01 /

回答:


288

Javaでオブジェクトを作成するには、4つの異なる方法があります。

Anewキーワードの使用
これは、Javaでオブジェクトを作成する最も一般的な方法です。オブジェクトのほぼ99%がこの方法で作成されます。

 MyObject object = new MyObject();

B。使用してClass.forName()
私たちは、クラスの名前を知っていると、それは公共のデフォルトコンストラクタを持っているならば、我々はこのようにオブジェクトを作成することができます。

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

C。使用してclone()
クローン()は既存のオブジェクトのコピーを作成するために使用することができます。

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

Dobject deserialization
オブジェクトの逆シリアル化の使用は、シリアル化された形式からオブジェクトを作成することに他なりません。

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

こちらから読むことができます


10
したがって、実際には2つの方法しか存在しません。コンストラクターの呼び出し(new、clone()またはリフレクションを使用)と、コンストラクターを呼び出さない非直列化です。
AlexR

13
@AlexR:Object.clone()コンストラクタも呼び出しません。
axtavt

1
これが一番の答えのようですので、配列の作成をサブケースとしてAとBに追加できますか?(詳細については私の回答を参照してください)。
–PaŭloEbermann、2011

逆シリアル化はコンストラクターを呼び出しますが、最も派生した型ではありません。
トムホーティン-タックライン

2
またConstructor、を一般化するクラスについても言及する必要がありClass.newInstanceます。
templatetypedef

68

さまざまな方法があります。

  • を介してClass.newInstance
  • を介してConstructor.newInstance
  • 逆シリアル化(最も派生した非シリアル化可能な基本クラスの引数なしのコンストラクターを使用)。
  • を介してObject.cloneコンストラクタを呼び出さない)。
  • JNIを介して(コンストラクターを呼び出す必要があります)。
  • を呼び出す他のメソッドを通じてnew
  • クラスローディングを新しいオブジェクト(intern Stringのような)を作成することとして説明できると思います。
  • 宣言の初期化の一部としてのリテラル配列(配列のコンストラクターなし)。
  • "varargs"(...)メソッド呼び出しの配列(配列のコンストラクターなし)。
  • 非コンパイル時定数の文字列連結(通常の実装では、少なくとも4つのオブジェクトが生成される可能性があります)。
  • 例外が作成され、ランタイムによってスローされます。たとえばthrow null;または"".toCharArray()[0]
  • もちろん、プリミティブのボクシング(キャッシュされていない場合)はもちろんです。
  • JDK8には、暗黙的にオブジェクトに変換されるラムダ(本質的には簡潔な匿名の内部クラス)が必要です。
  • 完全性(およびPaandlo Ebermann)のために、newキーワードを使用した構文もいくつかあります。

6
「通常の方法」も追加する必要があります:-)
–PaŭloEbermann '25

@PaŭloEbermannそれはとても古い学校で、クールではありません。(質問の意味するところは「コンストラクターを使用することです(上記のすべてではありませんが、コンストラクターを行のどこかで使用します)」
Tom Hawtin-タックライン

実際には3つの方法しかありません。そのためにコメントを追加しました
bestsss

3
見逃しました:java.misc.Unsafe.allocateInstance()。それはいくつかの理由で厄介ですが。そして、実際には、逆シリアル化は引数なしのコンストラクターを使用しません。ボンネットの下ではallocateInstance、同等の黒魔術を使用しています。
スティーブンC

最良の答えはまだですが、JNI AllocObject().はコンストラクターを呼び出しません。
ローン侯爵、2015

25

Java言語内では、オブジェクトを作成する唯一の方法は、コンストラクターを明示的または暗黙的に呼び出すことです。リフレクションの結果を使用してコンストラクターメソッドを呼び出し、逆シリアル化はリフレクションを使用してコンストラクターを呼び出し、ファクトリーメソッドはコンストラクターへの呼び出しをラップして実際の構築を抽象化し、複製は同様にラップされたコンストラクター呼び出しです。


1
不正解です。Deserializatioは、明示的または暗黙的にクラスのコンストラクターを呼び出しません。
ローン侯爵、2015

2
私は「そのコンストラクタ」と「コンストラクタ」ではなく、「コンストラクタ」と「コンストラクタ」を書くべきでした。逆シリアル化の場合、最初に適用可能な引数なしのコンストラクターが常に呼び出されます。
2015

1
デフォルトのクローン実装はコンストラクターを呼び出しません。
Didier L

これが私の複製メソッドの実装である場合は、「return super.clone();」。その後、コンストラクターは呼び出されません。
Mateen

13

はい、リフレクションを使用してオブジェクトを作成できます。たとえば、String.class.newInstance()は新しい空のStringオブジェクトを提供します。


1
これを使用すると、try / catchブロックで囲むように求められます。
GuruKulki

2
はい、例外がスローされるケースはたくさんあります。問題の原因の例については、newInstance()のJavaDocを参照してください。
ThomasLötzer、2010年

11

Javaでオブジェクトを作成するには、5つの異なる方法があります。

1. newキーワードを使用して →コンストラクターを呼び出す

Employee emp1 = new Employee();

2.newInstance()Class →コンストラクタのメソッドを使用して呼び出される

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

次のように書くこともできます

Employee emp2 = Employee.class.newInstance();

3.newInstance()Constructor →コンストラクタのメソッドを使用して呼び出される

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

4. clone()メソッドの使用 →コンストラクター呼び出しなし

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

5.逆シリアル化の使用 →コンストラクター呼び出しなし

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

最初の3つのメソッドのnewキーワードと両方newInstance()にコンストラクター呼び出しが含まれていますが、後の2つのcloneメソッドと逆シリアル化メソッドは、コンストラクターを呼び出さずにオブジェクトを作成します。

上記のすべてのメソッドには、異なるバイトコードが関連付けられています。例と詳細な説明(これらすべてのメソッドのバイトコード変換など)については、例を使用してJavaでオブジェクトを作成するさまざまな方法をお読みください。

ただし、配列または文字列オブジェクトの作成はオブジェクトの作成方法でもあると主張できますが、これらはいくつかのクラスにのみ固有であり、JVMによって直接処理されますが、これらの5つの方法を使用して任意のクラスのオブジェクトを作成できます。


所属を開示し、投稿を通じてサイトを宣伝する手段としてサイトを使用しないでください。良い答えを書くにはどうしたらいいですか?をご覧ください
イベット-モニカを



6

これは、Javaを初めて使用する場合、すべてのオブジェクトがObjectから継承されていることに注意してください。

保護されたネイティブオブジェクトclone()はCloneNotSupportedExceptionをスローします。


@stacker:これが新しいオブジェクトの作成とどのように関連しているか説明していただけますか?ありがとう。
ryanprayogo 2010年

4
@ryanprayogo clone()は新しいオブジェクトを返し(オブジェクトがclone()が呼び出されたオブジェクトのクローンである場合でも)、実際にはコンストラクターを呼び出さずに新しいオブジェクトを作成する唯一の方法です。
ThomasLötzer、2010年

6

また、データをオブジェクトに逆シリアル化することもできます。これはクラスコンストラクターを通過しません!


更新:コメントで指摘してくれたトムに感謝します!そしてマイケルも実験した。

これは、最も派生した非シリアライズ可能なスーパークラスのコンストラクターを通過します。
また、そのクラスに引数なしのコンストラクタがない場合、逆シリアル化時にInvalidClassExceptionがスローされます。

すべてのケースの完全な処理についてはトムの回答を参照してください;-)
Javaで「新しい」キーワードを使用せずにオブジェクトを作成する他の方法はありますか


1
これは、コンストラクター(最も派生した非直列化可能スーパークラスの引数なしのコンストラクター)を通過します。
トム・ホーティン-10

1
@トムああすごい-私はそれを知らなかったし、少し実験した。どうやら、最も派生した非直列化可能スーパークラスに引数なしのコンストラクタがない場合、結果としてInvalidClassException がストリームに直列化され、直列化復元時にスローされます。-それはどのように奇妙ですか?
Michael Borgwardt、2010年

6

オブジェクトには、通常のインスタンス作成メカニズム(コンストラクターの呼び出し)では構築できないタイプの配列があります。配列は

 A[] array = new A[len];

または

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

Seanがコメントで述べたように、これは構文的にはコンストラクター呼び出しに似ており、内部的にはメモリブロックの割り当てとゼロ初期化(または2番目のケースでは明示的なコンテンツで初期化)にすぎません。タイプと長さ。

引数をvarargs-methodに渡すと、配列も暗黙的に作成(および設定)されます。

4番目の方法は

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

もちろん、クローンとデシリアライズもここで機能します。

標準APIには配列を作成する多くのメソッドがありますが、実際にはすべてこれらの方法の1つ(または複数)を使用しています。


もちろん、Arrayコンストラクタを定義することはできませんが、それ以外はメカニズムは同じnewキーワードです。Array.newInstanceは、ここでの唯一の新しいメカニズム
Sean Patrick Floyd

@Sean:同じキーワードですが、まったく異なる内部メカニズムです。
–PaŭloEbermann 2012

もちろんそうです。しかし一方で、配列作成のさまざまなバージョンは内部的にはほとんど同じです。ちょうどあなたの答えが2011年からだったことに気づきました。古いものをかき回してすみません:-)
ショーンパトリックフロイド

@Sean:問題ありません。この機会に文法の修正を行いました。
–PaŭloEbermann 2012

いい仕事です、配列についてここで誰も議論しませんでした!
Mateen

5

私たちが徹底している場合、他の方法。

  • Oracle JVMにはUnsafe.allocateInstance()があり、コンストラクターを呼び出さずにインスタンスを作成します。
  • バイトコード操作を使用して、あなたがにコードを追加することができanewarraymultianewarraynewarrayまたはnew。これらは、ASMやBCELなどのライブラリを使用して追加できます。bcelのバージョンは、OracleのJavaに同梱されています。繰り返しになりますが、これはコンストラクターを呼び出しませんが、コンストラクターを別の呼び出しとして呼び出すことができます。


4

リフレクションもあなたのために仕事をします。

SomeClass anObj = SomeClass.class.newInstance();

クラスの新しいインスタンスを作成するもう1つの方法です。この場合、スローされる可能性のある例外も処理する必要があります。


4
  • new演算子の使用(したがって、コンストラクターの呼び出し)
  • リフレクションを使用するclazz.newInstance()(これもコンストラクタを呼び出す)。またはclazz.getConstructor(..).newInstance(..)(コンストラクタを使用しますが、どちらを選択するか)

オブジェクトのクラスのコンストラクターを呼び出すことによって、答えを要約するには-主な方法の1つ-

更新:別の回答では、コンストラクターの使用を含まない2つの方法(脱塩とクローニング)がリストされています。


4

Javaでオブジェクトを作成する方法は5つあります。

1. `new`キーワードを使用:

これは、Javaでオブジェクトを作成する最も一般的な方法です。オブジェクトのほぼ99%がこの方法で作成されます。

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

2.ファクトリーメソッドを使用して:

ClassName ObgRef=ClassName.FactoryMethod();

例:

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

3.クローニングの概念を使用して:

を使用するclone()と、clone()を使用して既存のオブジェクトのコピーを作成できます。

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

4. `Class.forName()`を使用:

クラスの名前がわかっていて、デフォルトのパブリックコンストラクターがある場合は、この方法でオブジェクトを作成できます。

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

例:

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

5.オブジェクトの逆シリアル化の使用:

オブジェクトの逆シリアル化は、シリアル化された形式からオブジェクトを作成することに他なりません。

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

(4)Class.forName()クラスがまだない場合にのみ必要です。クラスは他のすべての場合と同じです。また、引数のないコンストラクターも必要ありません。正しい引数がわかっている場合は、パブリックコンストラクターを呼び出す方法があります。そして、あなたは少なくとも2つの他の方法を省略しました。
ローン侯爵

2
(2)Factoryメソッドは、オブジェクトを取得するための単なるパターンです。しかし内部的には、オブジェクトの作成に「新しい」キーワードを使用します。
Karthik Bose

なぜファクトリーメソッドはオブジェクトを作成すると言っている人が多いのですか?
Mateen

3

既存のオブジェクトを複製することもできます(Cloneableを実装している場合)。

Foo fooClone = fooOriginal.clone (); 

2

方法1

新しいキーワードを使用します。これは、Javaでオブジェクトを作成する最も一般的な方法です。オブジェクトのほぼ99%がこの方法で作成されます。

Employee object = new Employee();

方法2

Class.forName()を使用します。Class.forName()は、リフレクションに役立つクラスオブジェクトを提供します。このオブジェクトが持つメソッドは、クラスを作成するプログラマーではなく、Javaによって定義されます。どのクラスでも同じです。その上でnewInstance()を呼び出すと、そのクラスのインスタンスが提供されます(つまり、callingClass.forName( "ExampleClass")。newInstance()は、クラスが定義するメソッドを呼び出すことができるnew ExampleClass()を呼び出すことと同じです。可視フィールドなどにアクセスします

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

ClassLoader.loadClass()は別のClassLoaderを指定できますが、Class.forName()は常に呼び出し元のClassLoaderを使用します。Class.forNameはロードされたクラスも初期化すると思いますが、ClassLoader.loadClass()アプローチはすぐには実行しません(最初に使用されるまで初期化されません)。

別の人は読む必要があります:

Java:単純なJava列挙型の例を使用したスレッド状態の概要

方法3

clone()を使用します。clone()を使用して、既存のオブジェクトのコピーを作成できます。

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

方法4

newInstance()メソッドの使用

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

方法5

オブジェクトの逆シリアル化の使用。オブジェクトの逆シリアル化は、シリアル化された形式からオブジェクトを作成することに他なりません。

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

コードではないテキストにコード形式を使用しないでください。これらよりも多くの方法があります。他の答えを読んでください。「ほぼ99%」は単なる推測です。
ローン侯爵2015

申し訳ありませんが、この間違いのために...私はこれがちょうどmodel..and申し訳ありませんがalearnerと新しいものの権利one.ItsはStackOverflowのために、正確に言っていないオブジェクトを作成する方法の一種であると述べたEJPのHi
Andriya

0

APIユーザーの観点から見ると、コンストラクターの別の代替手段は静的なファクトリーメソッド(BigInteger.valueOf()など)ですが、APIの作成者(および技術的には「実際」)の場合、オブジェクトは引き続きコンストラクターを使用して作成されます。


-1

あなたが作成によってあなたが意味するものに正確に依存しますが、他のいくつかは次のとおりです:

  • クローン方式
  • 逆シリアル化
  • リフレクション(Class.newInstance())
  • リフレクション(Constructorオブジェクト)

2
3と4は同じメカニズムの異なるエイリアスです
Sean Patrick Floyd

-2

ClassLoader.loadClass(s​​tring)もありますが、これはあまり使用されません。

そして、それについて完全な弁護士になりたい場合、配列は.lengthプロパティがあるため、技術的にはオブジェクトです。したがって、配列を初期化するとオブジェクトが作成されます。


1
loadClass(String name)は、オブジェクトyesである結果のClassオブジェクトを返しますが、そのクラスのオブジェクトは返しません。例が示されている場合、Javaライブラリ全体にそのような例が多数ありますが、それらはクラス固有です。youtu.be/gGGCmrD6Qpwを
nanosoft 2017

-3

オブジェクトは5つの方法で作成できます。

  1. 新しいオペレーターによる
  2. リフレクション(例:Class.forName()に続いてClass.newInstance())
  3. 工場法による
  4. クローニングによって
  5. リフレクションAPI

3
Class.forName()は、オブジェクトを作成するのではなく、クラスをロードします。
ローン侯爵

反射?確かにあなたは反射を意味します。
スティーブンC

どのようにファクトリメソッドからオブジェクトを作成しますか?内部実装は新しいキーワードを再び使用しているかもしれませんか?そしてなぜあなたは二度反射を持っていますか?実際にいくつかの例を挙げればもっと理にかなっています
Mateen

-5

この方法でオブジェクトを作成することもできます:-

String s ="Hello";

誰もそれを議論していません。


これは、プリミティブデータ型を作成する方法であり、Javaが「新しい」キーワードを使用しないようにバックグラウンドで提供する柔軟性です。これは、新しいキーワードと同じです。
Madusudanan 2014年

Madhusudan、FYI、newオペレーターの助けを借りて、オブジェクトは常にヒープに格納する必要がありますが、この場合、「Hello」は文字列プールに格納する必要があるオブジェクトです。また、Stringはプリミティブデータ型ではなくクラスです。
Deepak Sharma 14年

これはオブジェクトを作成しません。参照を既存のオブジェクトに割り当てます。オブジェクトは、コンパイラとクラスローダーによってすでに作成されています。
ローン侯爵2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.