Каковы различные способы создания объекта в 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
Вы можете проверить ссылку, codesandlogics.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()
Clone () можно использовать для создания копии существующего объекта.

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

D . Использование object deserialization
десериализации объекта - это не что иное, как создание объекта из его сериализованной формы.

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

Вы можете прочитать их здесь .

kamaci
источник
10
Таким образом, на самом деле существует только 2 способа: вызов конструктора (с использованием new, clone () или отражения) и десериализация, которая не вызывает конструктор.
AlexR
13
@AlexR: Object.clone()тоже не вызывает конструктор.
Axtavt
1
Поскольку это, кажется, ответ на самом верху, не могли бы вы добавить создания массивов в качестве подслучаев для A и B? (Смотрите мой ответ для деталей).
Паŭло Эберманн
Десериализация вызывает конструктор, но не самого производного типа.
Том Хотин - tackline
2
Вы должны также упомянуть Constructorкласс, который обобщает Class.newInstance.
templatetypedef
68

Есть разные способы:

  • Через Class.newInstance.
  • Через Constructor.newInstance.
  • Посредством десериализации (использует конструктор без аргументов наиболее производного несериализуемого базового класса).
  • Через Object.clone( не вызывает конструктор ).
  • Через JNI (должен вызывать конструктор).
  • С помощью любого другого метода, который вызывает newдля вас.
  • Я предполагаю, что вы могли бы описать загрузку классов как создание новых объектов (таких как interned Strings).
  • Литеральный массив как часть инициализации в объявлении (нет конструктора для массивов).
  • Массив в ...вызове метода varargs ( ) (без конструктора для массивов).
  • Некомпиляция конкатенации строк с постоянной времени (в типичной реализации происходит как минимум четыре объекта).
  • Вызывает исключение, которое будет создано и выдано средой выполнения. Например throw null;или "".toCharArray()[0].
  • Да и бокс примитивов (если не кешируется), конечно.
  • JDK8 должен иметь лямбды (по существу, краткие анонимные внутренние классы), которые неявно преобразуются в объекты.
  • Для полноты (и Paŭlo Ebermann) есть также некоторый синтаксис с newключевым словом.
Том Хотин - Tackline
источник
6
Вы также должны добавить «нормальный путь» :-)
Paŭlo Ebermann
@ Paŭlo Ebermann Это такая старая школа и не крутая. (Я предполагал, что то, что подразумевается под вопросом «использовать конструктор (хотя большинство, но не все, из вышеперечисленного действительно используют конструктор / a где-то вдоль линии).)
Том Хотин - tackline
на самом деле есть только 3 реальных способа сделать это, для которых я добавил комментарий
bestsss
3
Вы пропустили один: java.misc.Unsafe.allocateInstance(). Хотя это неприятно по ряду причин. И фактически, десериализация не использует конструктор без аргументов. Под капотом он использует allocateInstanceили эквивалентную черную магию.
Стивен С.
Лучший ответ пока, но JNI AllocObject().не вызывает конструктор.
Маркиз Лорн
25

В языке Java единственный способ создать объект - вызвать его конструктор, явным или неявным образом. Используя отражение в результате вызова метода конструктора, десериализация использует отражение для вызова конструктора, фабричные методы заключают вызов в конструктор, чтобы абстрагировать фактическую конструкцию, и клонирование аналогично является вызовом конструктора в оболочке.

Спутанность сознания
источник
1
Неправильно. Deserializatio не вызывает конструктор класса ни явно, ни неявно.
Маркиз Лорн
2
Я не должен был писать «его конструктор» и «конструктор», а скорее «конструктор» и «конструктор». В случае десериализации всегда вызывается первый применимый конструктор без аргументов.
Беспорядок
1
Реализация клона по умолчанию не вызывает никакого конструктора.
Дидье Л
если это моя реализация метода клона "return super.clone ();". Тогда он не будет вызывать конструктор.
Mateen
13

Да, вы можете создавать объекты с помощью отражения. Например, String.class.newInstance()даст вам новый пустой объект String.

Томас Лётцер
источник
1
если я использую это, то просит меня заключить в блок try / catch.
ГуруКульки
2
Да, есть много случаев, когда исключения могут быть выброшены. См. JavaDoc для newInstance () для примеров того, что может пойти не так.
Томас Лётцер
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, вызывается

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

Также вы можете использовать

 Object myObj = Class.forName("your.cClass").newInstance();
Винсент Рамдхани
источник
6

Это следует заметить, если вы новичок в Java, каждый объект унаследовал от объекта

Защищенный нативный объект clone () создает исключение CloneNotSupportedException;

укладчик
источник
@stacker: Не могли бы вы объяснить, как это связано с созданием нового объекта? Спасибо.
ryanprayogo
4
@ryanprayogo clone () вернет новый объект (даже если этот объект является клоном объекта, к которому был вызван clone ()) и фактически является единственным способом создания нового объекта без вызова конструктора.
Томас Лётцер
6

Также вы можете десериализовать данные в объект. Это не проходит через конструктор класса!


ОБНОВЛЕНО : Спасибо, Том, за то, что указал на это в своем комментарии! И Майкл тоже экспериментировал.

Он проходит через конструктор самого производного несериализуемого суперкласса.
И когда у этого класса нет конструктора без аргументов, при десериализации генерируется исключение InvalidClassException.

Пожалуйста, смотрите ответ Тома для полной обработки всех случаев ;-)
есть ли другой способ создания объекта без использования ключевого слова "new" в java

KLE
источник
1
Он проходит через конструктор (конструктор без аргументов наиболее производного несериализуемого суперкласса).
Том Хотин - Tackline
1
@ Том Ого, я этого не знал и немного поэкспериментировал. Очевидно, что когда самый производный несериализуемый суперкласс не имеет конструктора без аргументов, это приводит к тому, что InvalidClassException сериализуется в поток и генерируется при десериализации !! - Как странно это?
Майкл Боргвардт
6

Существует тип объекта, который не может быть создан обычными механизмами создания экземпляров (вызывающими конструкторами): массивы . Массивы создаются с

 A[] array = new A[len];

или

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

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

При передаче аргументов в varargs-метод там тоже создается (и заполняется) массив неявно.

Четвертый способ будет

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

Конечно, клонирование и десериализация работает и здесь.

В Стандартном API есть много методов, которые создают массивы, но все они фактически используют один (или более) из этих способов.

Пауло Эберманн
источник
Конечно, вы не можете определять конструкторы Array, но помимо этого механизм является тем же newключевым словом. Array.newInstance - единственный новый механизм здесь
Шон Патрик Флойд
@Sean: это то же самое ключевое слово, но это совершенно другой внутренний механизм, осмелюсь сказать.
Paŭlo Ebermann
Это правда, конечно. Но с другой стороны, разные версии создания массивов практически одинаковы. Только что понял, что ваш ответ был с 2011 года. Извините за разжигание старых вещей :-)
Шон Патрик Флойд
@Sean: Нет проблем, я воспользовался этим случаем, чтобы исправить грамматику.
Paŭlo Ebermann
отличная работа, никто не обсуждал здесь о массивах!
Матин
5

Другие способы, если мы исчерпывающие.

  • В Oracle JVM есть Unsafe.allocateInstance (), которая создает экземпляр без вызова конструктора.
  • Использование манипуляция байт - код , вы можете добавить код anewarray, multianewarray, newarrayили new. Они могут быть добавлены с использованием таких библиотек, как ASM или BCEL. Версия bcel поставляется с Oracle Java. Опять же, это не вызывает конструктор, но вы можете вызвать конструктор как отдельный вызов.
Питер Лори
источник
4

Отражение:

someClass.newInstance();
Джон Мигер
источник
4

Reflection также сделает всю работу за вас.

SomeClass anObj = SomeClass.class.newInstance();

это еще один способ создать новый экземпляр класса. В этом случае вам также потребуется обработать исключения, которые могут быть сгенерированы.

ryanprayogo
источник
4
  • используя newоператор (таким образом вызывая конструктор)
  • используя отражение clazz.newInstance()(которое снова вызывает конструктор). Или clazz.getConstructor(..).newInstance(..)(снова используя конструктор, но вы можете выбрать, какой из них)

Резюмировать ответ - один из основных способов - вызывая конструктор класса объекта.

Обновление: в другом ответе перечислены два способа, которые не связаны с использованием конструктора - десерализация и клонирование.

Bozho
источник
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) Фабричный метод - это просто шаблон для получения объектов. Но внутри он использует «новое» ключевое слово для создания объектов.
Картик Бозе
Человек, почему так много людей говорят, что фабричный метод создает объекты, откуда вы, ребята, учились этому?
Матин
3

Вы также можете клонировать существующий объект (если он реализует Cloneable).

Foo fooClone = fooOriginal.clone (); 
Римский
источник
2

Способ 1

Используя новое ключевое слово. Это наиболее распространенный способ создания объекта в Java. Почти 99% объектов созданы таким образом.

Employee object = new Employee();

Способ 2

Использование Class.forName (). Class.forName () предоставляет вам объект класса, который полезен для отражения. Методы этого объекта определяются Java, а не программистом, пишущим класс. Они одинаковы для всех классов. Вызов newInstance () для этого дает вам экземпляр этого класса (то есть, вызывающийClass.forName ("ExampleClass"). NewInstance () это эквивалентно вызову нового ExampleClass ()), в котором вы можете вызывать методы, которые определяет класс, доступ к видимым полям и т. д.

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

Class.forName () всегда будет использовать ClassLoader вызывающей стороны, тогда как ClassLoader.loadClass () может указывать другой 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();
Andriya
источник
Не используйте форматирование кода для текста, который не является кодом. Есть больше методов, чем эти. Прочитайте другие ответы. «Почти 99%» - это просто догадки.
Маркиз Лорн
Привет, EJP, извини за эту ошибку ... Я сказал, что это один из способов создания объектов, которые не совсем точно названы. Это просто модель. И извините, я alearner и новичок в stackoverflow
Андрия
0

С точки зрения пользователя API, другой альтернативой конструкторам являются статические фабричные методы (например, BigInteger.valueOf ()), хотя для автора API (и технически «для реального») объекты все еще создаются с использованием конструктора.

Фабиан Стиг
источник
-1

Зависит от того, что вы подразумеваете под созданием, но есть и другие:

  • Метод клонирования
  • Десериализация
  • Отражение (Class.newInstance ())
  • Отражение (объект-конструктор)
Гарт Гилмор
источник
2
3 и 4 - разные псевдонимы для одного и того же механизма
Шон Патрик Флойд
-2

есть также ClassLoader.loadClass (string), но это не часто используется.

и если вы хотите быть абсолютным юристом по этому поводу, технически массивы являются объектами из-за свойства массива .length. поэтому инициализация массива создает объект.

Рэнди Л
источник
1
loadClass (String name) возвращает результирующий объект Class, который является объектом yes, но не объектом этого класса. Если приведены примеры, то мы можем найти множество таких примеров в библиотеке java, но они будут специфичными для класса. проверьте youtu.be/gGGCmrD6Qpw
нанософт
-3

Мы можем создать объекты 5 способами:

  1. новым оператором
  2. отражением (например, Class.forName (), за которым следует Class.newInstance ())
  3. заводским методом
  4. клонированием
  5. по отражению API
Tanushree Рой
источник
3
Class.forName () загружает класс, а не создает объект.
Маркиз Лорн
отражение? Конечно, вы имеете в виду отражение.
Стивен С.
Как бы вы создали объект из метода фабрики, внутренняя реализация может снова использовать новое ключевое слово, верно? и почему у вас есть отражение дважды? Было бы больше смысла , если вы на самом деле дать некоторые exampls
Матин
-5

Мы также можем создать объект следующим образом:

String s ="Hello";

Никто не обсуждал это.

Дипак Шарма
источник
Это способ создания примитивных типов данных, это просто гибкость, которую Java обеспечивает за кулисами, чтобы не использовать ключевое слово «new». Это то же самое, что и ключевое слово new.
Мадусуданан
Madhusudan, FYI, С помощью оператора new объекты всегда должны храниться в куче, в то время как в этом случае «Hello» - это объект, который должен храниться в пуле строк. И String - это класс, а не примитивный тип данных.
Дипак Шарма
Это не создает объект. Он присваивает ссылку на существующий объект. Объект уже был создан компилятором и загрузчиком классов.
Маркиз Лорн