Які всі способи створити об’єкт на 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
є лише 3: нормальний c-tor (нове ключове слово), clone () та Unsafe.allocateInstance(Class). Решта називають одну з таких. Відображення складається для виклику c-tor, десеріалізації до Unsafe.allocateInstance (Class). Ви можете створити власний API, і ви в кінцевому підсумку зателефонуєте до одного з них.
bestsss

2
@ bestsss Unsafe- це конкретна детальна версія Java та не згадується ніде в специфікації. Цілком можливо побудувати слухняну реалізацію Java , яка не використовує компіляцію відображення вниз до коду , який використовує new, cloneабо Unsafe.allocateInstance.
templatetypedef

2
ви можете перевірити посилання, codeandlogics.com/2017/01/ways-to-create-objects-in-java.html
Pragya

Відповіді:


288

Існує чотири різні способи створення об’єктів у Java:

. Використання newключового слова
Це найпоширеніший спосіб створення об’єкта в 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();

D . Використання object deserialization
об’єкта деріаріалізації - це не що інше, як створення об'єкта з його серіалізованої форми.

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

Ви можете прочитати їх звідси .


10
Тож фактично існує лише два способи: виклик конструктора (використання нового, клонування () або відображення) та десеріалізація, що не викликає конструктор.
AlexR

13
@AlexR: Object.clone()теж не викликає конструктор.
axtavt

1
Оскільки це, здається, є відповіддю вгорі, чи можете ви додати створення масивів як підзастосування до A і B? (Деталі див. У моїй відповіді).
Paŭlo Ebermann

Десеріалізація посилається на конструктор, тільки не з найбільш похідного типу.
Том Хотін - тайклін

2
Ви також повинні згадати Constructorклас, який узагальнює Class.newInstance.
templatetypedef

68

Існують різні способи:

  • Через Class.newInstance.
  • Через Constructor.newInstance.
  • Через десеріалізацію (використовує конструктор no-args самого похідного базового класу несериалізації).
  • Через Object.clone( не викликає конструктор ).
  • Через JNI (слід викликати конструктора).
  • Через будь-який інший метод, який викликає newдля вас.
  • Я думаю, ви могли б описати завантаження класу як створення нових об'єктів (наприклад, інтернованих Strings).
  • Буквальний масив як частина ініціалізації в декларації (немає конструктора для масивів).
  • Масив у методі "varargs" ( ...) викликає (немає конструктора для масивів).
  • Незбірник конкатенації постійних строків часу (трапляється, щоб створити щонайменше чотири об'єкти за типової реалізації).
  • Викликаючи виняток для створення та викидання під час виконання. Наприклад, throw null;або "".toCharArray()[0].
  • Ой, і бокс примітивів (якщо не кешований), звичайно.
  • JDK8 повинен мати лямбда (фактично стислі анонімні внутрішні класи), які неявно перетворюються на об'єкти.
  • Для повноти (і Paŭlo Ebermann) також є синтаксис із newключовим словом.

6
Ви також повинні додати "звичайний спосіб" :-)
Paŭlo Ebermann

@ Paŭlo Ebermann Це така стара школа і неприхована. (Я припускав, що під питанням мається на увазі "використовувати конструктор (хоча більшість, але не всі, з перерахованих вище використовують / конструктор десь уздовж лінії)."
Том Хоутін - пропуск

насправді існує лише 3 реальні способи зробити це, до якого я додав коментар
bestsss

3
Ви пропустили один: java.misc.Unsafe.allocateInstance(). Хоча це противно з кількох причин. Насправді, десеріалізація не використовує конструктор no-args. Під кришкою він використовує allocateInstanceабо еквівалентну чорну магію.
Стівен C

Найкраща відповідь поки, але JNI AllocObject().не викликає конструктора.
Маркіз Лорн

25

У мові Java єдиний спосіб створити об'єкт - викликати його конструктор, будь то явно чи неявно. Використовуючи результати відображення, викликає метод конструктора, десеріалізація використовує відображення для виклику конструктора, фабричні методи обертають виклик конструктору, щоб абстрагувати фактичну конструкцію, а клонування - аналогічно завернутому виклику конструктора.


1
Неправильно. Deserializatio не називає конструктора класу ні явно, ні неявно.
Маркіз Лорн

2
Я не повинен був писати «його конструктор» і «конструктор», а швидше «конструктор» і «конструктор». У випадку десеріалізації завжди викликається перший застосовний конструктор no-arg.
Плутанина

1
Реалізація клону за замовчуванням не викликає жодного конструктора.
Дідьє Л

якщо це моя реалізація методу клонування "return super.clone ();". Тоді він не викличе конструктор.
Mateen

13

Так, ви можете створювати об'єкти за допомогою відображення. Наприклад, String.class.newInstance()дасть вам новий порожній об'єкт String.


1
якщо я використовую це, його просять укласти в блок "спробувати".
GuruKulki

2
Так, є багато випадків, коли винятки можна кинути. Дивіться JavaDoc для newInstance () для прикладів того, що може піти не так.
Thomas Lötzer

11

Існує п’ять різних способів створити об’єкт на Java,

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

Перші три newключові слова методу і обидва newInstance()включають виклик конструктора, але пізніше два методи клонування та десеріалізації створюють об'єкти без виклику конструктора.

Усі вищезазначені методи мають різні байт-коди, пов'язані з ними. Прочитайте різні способи створення об’єктів у Java за допомогою Прикладу для прикладів та більш детального опису, наприклад, перетворення байтових кодів усіх цих методів.

Однак можна стверджувати, що створення масиву або рядкового об'єкта також є способом створення об'єкта, але ці речі більш специфічні лише для деяких класів і безпосередньо обробляються JVM, тоді як ми можемо створити об'єкт будь-якого класу, використовуючи ці 5 способів.


Будь ласка, розкривайте будь-які приналежності та не використовуйте сайт як спосіб просування вашого сайту шляхом публікації. Див. Як написати гарну відповідь? .
Іветт



6

Це слід помітити, якщо ви новачок у Java, кожен об'єкт успадкував від Object

захищений нативний об’єктний клон () викидає CloneNotSupportedException;


@stacker: Чи можете ви поясніть, як це пов’язано зі створенням нового об’єкта? Дякую.
ryanprayogo

4
@ryanprayogo клон () поверне новий об'єкт (навіть незважаючи на те, що об’єкт - це клон об'єкта, до якого був викликаний clone ()) і є фактично єдиним способом створення нового об'єкта без виклику конструктора.
Thomas Lötzer

6

Крім того, ви можете де-серіалізувати дані в об’єкт. Це не проходить через клас Конструктор!


ОНОВЛЕНО : Дякую Тому, що вказав на це у вашому коментарі! І Майкл також експериментував.

Він проходить через конструктор найбільш похідного не серіалізаційного надкласу.
І коли у цього класу немає конструктора no-args, InvalidClassException викидається при де-серіалізації.

Перегляньте відповідь Тома для повного лікування всіх випадків ;-)
чи є інший спосіб створення об'єкта без використання "нового" ключового слова в java


1
Він дійсно проходить через конструктор (конструктор без аргументу найбільш похідного несериализуемого суперкласу).
Том Хотін - тайклін

1
@Tom Oh wow - я цього не знав і трохи експериментував. Мабуть, коли найбільш похідний не серіалізуючий суперклас не має конструктора без аргументів, це призводить до того, що InvalidClassException серіалізується в потік і кидається при десеріалізації !! - Як це химерно?
Майкл Боргвардт

6

Існує тип об'єкта, який неможливо побудувати за допомогою звичайних механізмів створення екземплярів (викликають конструктори): масиви . Масиви створюються за допомогою

 A[] array = new A[len];

або

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

Як зазначив Шон у коментарі, це синтаксично схоже на виклик конструктора, і внутрішньо це не набагато більше, ніж виділення та ініціалізація нуля (або ініціалізація з явним вмістом, у другому випадку) блоком пам'яті, з деяким заголовком для позначення тип та довжина.

При передачі аргументів методу varargs, масив також створюється (і заповнюється) неявно.

Це був би четвертий шлях

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

Звичайно, тут працює і клонування, і десеріалізація.

У стандартному API існує багато методів, які створюють масиви, але всі вони фактично використовують один (або більше) цих способів.


Зрозуміло, ви не можете визначити конструктори масиву, але крім цього механізм - це те саме newключове слово. Array.newInstance - єдиний тут новий механізм
Шон Патрік Флойд

@Sean: Це одне і те ж ключове слово, але це зовсім інший внутрішній механізм, смію сказати.
Paŭlo Ebermann

Це правда, звичайно. Але з іншого боку, різні версії створення масиву всередині майже однакові. Щойно зрозумів, що ваша відповідь була з 2011 р. Вибачте за те, що розгорнули старі речі :-)
Шон Патрік Флойд

@Sean: Немає проблем, я використовував цей привід, щоб зробити виправлення граматики.
Paŭlo Ebermann

приємна робота, тут ніхто не обговорював масивів!
Mateen

5

Інші способи, якщо ми вичерпні.

  • У Oracle JVM є Unsafe.allocateInstance (), який створює екземпляр без виклику конструктора.
  • Використання маніпуляція байт - код , ви можете додати код anewarray, multianewarray, newarrayабо new. Вони можуть бути додані за допомогою бібліотек, таких як ASM або BCEL. Версія bcel поставляється з Java Oracle. Знову це не викликає конструктор, але ви можете викликати конструктор як окремий виклик.


4

Рефлексія теж зробить роботу за вас.

SomeClass anObj = SomeClass.class.newInstance();

є ще одним способом створення нового примірника класу. У цьому випадку вам також потрібно буде обробити винятки, які можуть бути кинуті.


4
  • за допомогою newоператора (таким чином викликаючи конструктор)
  • за допомогою рефлексії clazz.newInstance()(яка знову викликає конструктор). Або шляхом clazz.getConstructor(..).newInstance(..)(знову ж таки, використовуючи конструктор, але ви можете таким чином вибрати, який саме)

Узагальнити відповідь - один основний спосіб - шляхом виклику конструктора класу об’єкта.

Оновлення: Ще одна відповідь перераховувала два способи, які не передбачають використання конструктора - десералізацію та клонування.


4

Є п'ять різних способів створення об’єктів на Java:

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) Фабричний метод - лише схема отримання об'єктів. Але внутрішньо він використовує "нове" ключове слово для створення об'єктів.
Karthik Bose

чоловіче, чому так багато людей говорять, що фабричний метод створює об'єкти, звідки ви це дізналися?
Мейтен

3

Ви також можете клонувати існуючий об’єкт (якщо він реалізує Cloneable).

Foo fooClone = fooOriginal.clone (); 

2

Спосіб 1

Використання нового ключового слова. Це найпоширеніший спосіб створення об’єкту в Java. Майже 99% об’єктів створені таким чином.

Employee object = new Employee();

Спосіб 2

Використання Class.forName (). Class.forName () дає вам об’єкт класу, який корисний для роздумів. Методи, якими володіє цей об’єкт, визначаються Java, а не програміст, що пише клас. Вони однакові для кожного класу. Виклик newInstance () дає вам екземпляр цього класу (тобто callClass.forName ("ExampleClass"). NewInstance () еквівалентний виклику нового ExampleClass ()), за допомогою якого ви можете викликати методи, які визначає клас, отримати доступ до видимих ​​полів тощо.

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

Class.forName () завжди використовуватиме ClassLoader абонента, тоді як ClassLoader.loadClass () може вказати інший ClassLoader. Я вважаю, що Class.forName також ініціалізує завантажений клас, тоді як підхід ClassLoader.loadClass () робить це не відразу (він не ініціалізується до першого використання).

Інший повинен прочитати:

Java: Вступ стану потоку з прикладом Простий приклад Java Enum

Спосіб 3

Використовуючи клон (). Клон () може бути використаний для створення копії наявного об'єкта.

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%" - це лише здогадки.
Маркіз Лорн

Привіт EJP, вибачте за цю помилку ... Я сказав, що це один із способів створення об'єктів, не сказаних саме його правильним. Це просто модель .. І вибачте, я навмисний і новий для stackoverflow
Андрія

0

З точки зору користувача API, іншою альтернативою конструкторам є статичні заводські методи (наприклад, BigInteger.valueOf ()), хоча для автора API (а технічно "для реальних") об'єкти все ще створюються за допомогою конструктора.


-1

Залежить саме те, що ви маєте на увазі під створенням, але деякі інші:

  • Клонний метод
  • Десеріалізація
  • Рефлексія (Class.newInstance ())
  • Рефлексія (об’єкт конструктора)

2
3 і 4 - різні псевдоніми для одного і того ж механізму
Шон Патрік Флойд

-2

є також ClassLoader.loadClass (рядок), але це не часто використовується.

і якщо ви хочете бути повним юристом щодо цього, масиви технічно є об'єктами через властивість .length масиву. тому ініціалізація масиву створює об'єкт.


1
loadClass (ім'я рядка) повертає отриманий об'єкт Class, який є об'єктом так, але не об'єктом цього класу. Якщо наведено приклади, то їх можна знайти чимало таких прикладів у всій бібліотеці Java, але вони будуть специфічними для класу. перевірити youtu.be/gGGCmrD6Qpw
nanosoft

-3

Ми можемо створити об’єкти 5 способами:

  1. від нового оператора
  2. за допомогою відображення (наприклад, Class.forName (), а потім Class.newInstance ())
  3. заводським методом
  4. шляхом клонування
  5. за відображенням api

3
Class.forName () завантажує клас, а не створює об'єкт.
Маркіз Лорнський

рефлексія? Звичайно, ви маєте на увазі рефлексію.
Стівен C

як би ви створили об’єкт із заводського методу, внутрішня реалізація може бути знову використовуючи нове ключове слово, правильно? і чому у вас є роздуми двічі? Було б більше сенсу , якщо ви на самому справі дати деякі exampls
Матін

-5

Ми також можемо створити об'єкт таким чином:

String s ="Hello";

Ніхто не обговорював це.


Це спосіб створення примітивних типів даних, це просто гнучкість, яку забезпечує Java за лаштунками, щоб не використовувати "нове" ключове слово. Це те саме, що і нове ключове слово.
Мадуданан

Madhusudan, FYI, За допомогою нового оператора об'єкти завжди повинні зберігатися в купі, в цьому випадку "Hello" - це об'єкт, який повинен зберігатися в String pool. І String - це клас не примітивний тип даних.
Діпак Шарма

Це не створює об'єкт. Він призначає посилання на існуючий об’єкт. Об'єкт уже створено компілятором і завантажувачем.
Маркіз Лорн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.