Java로 객체를 만드는 다른 방법은 무엇입니까?


178

다른 날 동료와 대화를 나 Ha습니다.

생성자를 사용하는 것이 명백하지만 다른 방법은 무엇입니까?


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)있습니다. 나머지는 그 중 하나를 호출합니다. 리플렉션은 c-tor 호출로 컴파일되고 Unsafe.allocateInstance (Class)로 직렬화 해제됩니다. 당신은 당신의 자신의 API를 만들 수 있으며 결국 그 중 하나를 호출하게됩니다.
bestsss

2
@ bestsss- Unsafe는 Java의 구현 별 세부 사항이며 사양의 어느 곳에서도 언급되지 않았습니다. 이 코드를 그 용도에 컴파일 반사 아래로 사용하지 않는 준수 자바 구현 구축 전적으로 가능하다 new, clone또는를 Unsafe.allocateInstance.
templatetypedef


답변:


288

자바에서 객체를 생성하는 방법은 4 가지가 있습니다 :

. new키워드 사용
이것은 자바에서 객체를 생성하는 가장 일반적인 방법입니다. 이런 방식으로 객체의 거의 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();

여기 에서 읽을 수 있습니다 .


10
따라서 실제로는 생성자 호출 (new, clone () 또는 reflection 사용)과 생성자를 호출하지 않는 역 직렬화의 두 가지 방법 만 있습니다.
AlexR

13
@AlexR : Object.clone()생성자도 호출하지 않습니다.
axtavt

1
이것이 맨 위의 대답 인 것처럼 배열의 생성을 A 및 B의 하위 사례로 추가 할 수 있습니까? (자세한 내용은 내 답변을 참조하십시오).
Paŭlo Ebermann

역 직렬화는 가장 파생 된 형식이 아닌 생성자를 호출합니다.
Tom Hawtin-tackline

2
또한 Constructor일반화 되는 클래스를 언급해야합니다 Class.newInstance.
templatetypedef

68

다양한 방법이 있습니다 :

  • 를 통해 Class.newInstance.
  • 를 통해 Constructor.newInstance.
  • 역 직렬화 (가장 파생 된 직렬화 할 수없는 기본 클래스의 인수 없음 생성자를 사용)를 통해
  • 통해 Object.clone( 생성자를 호출하지 않습니다 ).
  • JNI를 통해 (생성자를 호출해야 함)
  • 를 호출하는 다른 방법을 통해 new.
  • 클래스로드를 새 객체 (예 : interned String) 를 만드는 것으로 설명 할 수 있다고 생각합니다 .
  • 선언 초기화의 일부인 리터럴 배열 (배열 생성자 없음)
  • "varargs"( ...) 메소드 호출 의 배열 (배열에 대한 생성자 없음).
  • 비 컴파일 시간 상수 문자열 연결 (일반적인 구현에서 4 개 이상의 객체를 생성해야 함).
  • 런타임에서 예외를 작성하여 발생시킵니다. 예를 들어 throw null;또는 "".toCharArray()[0].
  • 물론 프리미티브 복싱 (캐시되지 않은 경우).
  • JDK8에는 람다 (본질적으로 간결한 익명 내부 클래스)가 있어야하며 이는 암시 적으로 객체로 변환됩니다.
  • 완성도 (및 Paŭlo Ebermann)를 위해 new키워드에 대한 구문 도 있습니다.

6
당신은 :-) 역시 "일반적인 방법"을 추가한다
파울로 Ebermann에게

@ Paŭlo Ebermann 너무 오래된 학교이고 냉담합니다. (질문의 의미가 "생성자를 사용한다 (위의 대부분은 아니지만 일부는 줄을 따라 어딘가에 생성자를 사용하지만))
Tom Hawtin-tackline

실제로 그것을 할 수있는 3 가지 실제 방법이 있습니다. 내가 코멘트를 추가했습니다
bestsss

3
당신은 하나를 놓쳤다 : java.misc.Unsafe.allocateInstance(). 여러 가지 이유로 불쾌하지만. 실제로 deserialization은 no-args 생성자를 사용하지 않습니다. 후드 아래에서 allocateInstance블랙 매직을 사용합니다.
Stephen C

아직 가장 좋은 대답이지만 JNI AllocObject().는 생성자를 호출하지 않습니다.
Lorne의 후작

25

Java 언어 내에서 객체를 생성하는 유일한 방법은 명시 적 또는 암시 적으로 생성자를 호출하는 것입니다. 리플렉션 결과를 사용하여 생성자 메서드를 호출하면 deserialization은 리플렉션을 사용하여 생성자를 호출하고 팩토리 메서드는 생성자를 호출하여 래핑하여 실제 생성을 추상화하며 복제는 래핑 된 생성자 호출과 비슷합니다.


1
잘못되었습니다. Deserializatio는 클래스의 생성자를 명시 적 또는 암시 적으로 호출하지 않습니다.
Lorne의 후작

2
'생성자'와 '생성자'를 쓰지 말고 '생성자'와 '생성자'를 작성해야합니다. 역 직렬화의 경우 첫 번째 적용 가능한 인수 없음 생성자가 항상 호출됩니다.
혼란

1
기본 클론 구현은 생성자를 호출하지 않습니다.
Didier L

이것이 내 클론 메소드 구현 인 경우 "return super.clone ();". 그런 다음 생성자를 호출하지 않습니다.
Mateen

13

예, 리플렉션을 사용하여 객체를 만들 수 있습니다. 예를 들어 String.class.newInstance()비어있는 새로운 String 객체를 제공합니다.


1
내가 이것을 사용하면 try / catch 블록으로 묶을 것을 요구합니다.
GuruKulki

2
예, 예외가 발생할 수있는 경우가 많습니다. 무엇이 잘못 될 수 있는지에 대한 예제는 newInstance ()에 대한 JavaDoc을 참조하십시오.
Thomas Lötzer

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

deserialization 사용 → 생성자 호출 없음

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

처음 세 개의 메소드 new키워드와 둘 다 newInstance()생성자 호출을 포함하지만 나중에 두 개의 복제 및 역 직렬화 메소드는 생성자를 호출하지 않고 오브젝트를 작성합니다.

위의 모든 메소드에는 서로 다른 바이트 코드가 있습니다. 를 들어 Java로 객체를 작성하는 다른 방법 읽기 예 및 더 자세한 설명, 예를 들어 이러한 모든 메소드의 바이트 코드 변환.

그러나 배열이나 문자열 객체를 만드는 것도 객체를 만드는 방법이라고 주장 할 수 있지만 이러한 것들은 일부 클래스에만 더 구체적이며 JVM에 의해 직접 처리되지만 우리는이 5 가지 방법을 사용하여 모든 클래스의 객체를 만들 수 있습니다.


제휴 관계를 공개하고 사이트를 게시를 통해 사이트를 홍보하는 방법으로 사용하지 마십시오. 좋은 답변을 작성하려면 어떻게합니까?를 참조하십시오 . .
Yvette-복직 모니카



6

Java를 처음 사용하는 경우 모든 객체가 Object에서 상속 된 경우이 사실을 알아야합니다

보호 된 네이티브 객체 clone ()은 CloneNotSupportedException을 던집니다.


@stacker : 이것이 새로운 객체 생성과 어떤 관련이 있는지 설명해 주시겠습니까? 감사.
ryanprayogo

4
@ryanprayogo clone ()은 새 객체를 반환하지만 (객체는 clone ()이 호출 된 객체의 복제본 임에도 불구하고) 실제로 생성자가 호출되지 않고 새 객체를 생성하는 유일한 방법입니다.
Thomas Lötzer

6

또한 데이터를 개체로 직렬화 해제 할 수 있습니다 . 이것은 생성자 클래스를 거치지 않습니다!


업데이트 : 의견에 지적 해 주셔서 감사합니다. 그리고 마이클도 실험했습니다.

가장 파생되지 않은 직렬화 가능 슈퍼 클래스의 생성자를 거치게됩니다.
그리고 해당 클래스에 인수 없음 생성자가 없으면 직렬화 해제시 InvalidClassException이 발생합니다.

모든 경우에 대한 완전한 처리는 Tom의 답변을 참조하십시오 ;-)
java에서 "new"키워드를 사용하지 않고 객체를 만드는 다른 방법이 있습니까?


1
생성자 (가장 파생 된 직렬화 할 수없는 슈퍼 클래스의 인수가없는 생성자)를 거치게됩니다.
Tom Hawtin-tackline

1
@ Tom Oh 와우-나는 그것을 몰랐고 조금 실험했다. 가장 많이 파생 된 직렬화 불가능한 수퍼 클래스에 인수없는 생성자 가없는 경우 , InvalidClassException 이 스트림으로 직렬화되고 직렬화 해제시 발생합니다. -얼마나 기괴한가요?
Michael Borgwardt

6

일반적인 인스턴스 생성 메커니즘 (생성자 호출)으로 구성 할 수없는 객체 유형이 있습니다 : Arrays . 배열은

 A[] array = new A[len];

또는

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

Sean이 의견에서 말했듯이, 이것은 구문 적으로 생성자 호출과 유사하며 내부적으로 메모리 블록을 할당하고 초기화하지 않는 (또는 두 번째 경우 명시 적 내용으로 초기화하는 것) 그 이상의 것이 아닙니다. 유형과 길이.

varargs-method에 인수를 전달할 때 배열도 암시 적으로 만들어지고 채워집니다.

네 번째 방법은

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

물론 복제 및 역 직렬화도 여기에서 작동합니다.

표준 API에는 배열을 생성하는 많은 메소드가 있지만 실제로는 이러한 방식 중 하나 이상을 사용하고 있습니다.


물론 배열 생성자를 정의 할 수는 없지만 메커니즘과 동일한 new키워드입니다. Array.newInstance는 여기에서 유일한 새로운 메커니즘입니다
Sean Patrick Floyd

@Sean : 같은 키워드이지만 완전히 다른 내부 메커니즘입니다.
Paŭlo Ebermann

물론 그렇습니다. 그러나 다른 버전의 어레이 생성은 내부적으로 거의 동일합니다. 당신의 대답은 2011 년이라는 것을 깨달았습니다. 오래된 것들을 감동 시켜서 죄송합니다. –-
Sean Patrick Floyd

@Sean : 문제 없습니다. 문법 수정을 위해이 기회를 이용했습니다.
Paŭlo Ebermann

좋은 직업, 아무도 배열에 대해 여기에서 논의하지 않았습니다!
Mateen

5

우리가 철저한 다른 방법.

  • Oracle JVM에는 Unsafe.allocateInstance ()가 있으며 생성자를 호출하지 않고 인스턴스를 만듭니다.
  • 사용 바이트 코드 조작 당신은에 코드를 추가 할 수 있습니다 anewarray, multianewarray, newarray또는 new. ASM 또는 BCEL과 같은 라이브러리를 사용하여 추가 할 수 있습니다. bcel 버전은 Oracle Java와 함께 제공됩니다. 다시 이것은 생성자를 호출하지 않지만 생성자를 별도의 호출로 호출 할 수 있습니다.


4

리플렉션도 당신을 위해 일할 것입니다.

SomeClass anObj = SomeClass.class.newInstance();

클래스의 새 인스턴스를 만드는 또 다른 방법입니다. 이 경우, 발생할 수있는 예외를 처리해야합니다.


4
  • 은 USING new연산자 (따라서 생성자 호출)
  • 리플렉션 사용 clazz.newInstance()(생성자를 다시 호출). 또는 clazz.getConstructor(..).newInstance(..)(생성자를 사용하지만 어느 것을 선택할 수 있는지)

객체 클래스의 생성자를 호출하여 답변을 요약합니다.

업데이트 : 또 다른 답변은 생성자를 사용하지 않는 두 가지 방법 인 deseralization 및 cloning을 나열했습니다.


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

`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()수업이없는 경우 에만 필요 하며 다른 모든 경우에는 수업이 있습니다. 또한 인수없는 생성자가 필요하지 않습니다. 올바른 인수를 알고 있으면 공용 생성자를 호출하는 방법이 있습니다. 그리고 적어도 두 가지 다른 방법을 배제했습니다.
Lorne의 후작

2
(2) 팩토리 메소드는 오브젝트를 가져 오기위한 패턴입니다. 그러나 내부적으로는 객체를 만들기 위해 "new"키워드를 사용합니다.
Karthik Bose

왜 많은 사람들이 팩토리 메소드가 객체를 생성한다고 말하는가?
Mateen

3

기존 객체를 복제 할 수도 있습니다 (복제 가능을 구현하는 경우).

Foo fooClone = fooOriginal.clone (); 

2

방법 1

새 키워드를 사용합니다. 이것은 자바에서 객체를 생성하는 가장 일반적인 방법입니다. 이런 방식으로 객체의 거의 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();

Class.forName ()은 항상 호출자의 ClassLoader를 사용하지만 ClassLoader.loadClass ()는 다른 ClassLoader를 지정할 수 있습니다. Class.forName은로드 된 클래스도 초기화하는 반면 ClassLoader.loadClass () 접근 방식은 즉시 수행하지 않습니다 (처음으로 사용될 때까지 초기화되지 않음).

다른 사람은 다음을 읽어야합니다.

Java : 간단한 Java Enum 예제를 사용한 스레드 상태 소개

방법 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 %'는 단순한 추측입니다.
Lorne의 후작

이 실수 죄송 EJP 안녕하세요 ... 나는이 개체를 만들 수있는 방법의 한 종류는 정확히 그 권리 one.Its 단지 model..and 죄송 오전 alearner와 새에 유래라고 말했다
Andriya

0

API 사용자 관점에서 생성자에 대한 또 다른 대안은 정적 팩토리 메소드 (예 : BigInteger.valueOf ())이지만 API 작성자 (기술적으로 "실제")의 경우 오브젝트는 여전히 생성자를 사용하여 작성됩니다.


-1

작성의 의미에 따라 다르지만 다른 것들은 다음과 같습니다.

  • 복제 방법
  • 역 직렬화
  • 반영 (Class.newInstance ())
  • 반사 (생성자 객체)

2
3과 4는 같은 메커니즘에 대해 서로 다른 별명
숀 패트릭 플로이드

-2

ClassLoader.loadClass (string)도 있지만 자주 사용되지는 않습니다.

그리고 당신이 그것에 대해 총 변호사가되고 싶다면, 배열은 .length 속성 때문에 기술적으로 객체입니다. 따라서 배열을 초기화하면 객체가 생성됩니다.


1
loadClass (String name)는 결과 클래스 객체를 반환하지만 객체는 해당 클래스의 객체는 아닙니다. 예제가 제공되면 Java 라이브러리 전체에서 이러한 예제를 찾을 수 있지만 클래스별로 다릅니다. youtu.be/gGGCmrD6Qpw
nanosoft

-3

5 가지 방법으로 객체를 만들 수 있습니다.

  1. 새로운 운영자에 의해
  2. 리플렉션 (예 : Class.forName () 다음에 Class.newInstance ())
  3. 공장 방법으로
  4. 복제함으로써
  5. 반사 API에 의해

3
Class.forName ()은 객체를 생성하지 않고 클래스를로드합니다.
Lorne의 후작

감상? 분명히 당신은 반성을 의미합니다.
Stephen C

팩토리 메소드에서 객체를 어떻게 작성합니까? 내부 구현에서 새로운 키워드를 다시 사용하고 있습니까? 왜 반사가 두 번 있습니까? 실제로 몇 개의 exampls를 제공하면 더 의미가 있습니다
Mateen

-5

이런 식으로 객체를 만들 수도 있습니다 :-

String s ="Hello";

아무도 그것에 대해 토론하지 않았습니다.


이는 원시 데이터 유형을 작성하는 방법으로, "새"키워드를 사용하지 않도록 Java가 배후에서 제공하는 유연성 일뿐입니다. 이는 새 키워드와 동일합니다.
Madusudanan 2016 년

Madhusudan, FYI, 새로운 연산자의 도움으로 객체는 항상 힙에 저장해야하지만이 경우 "Hello"는 문자열 풀에 저장해야하는 객체입니다. 그리고 String은 기본 데이터 유형이 아닌 클래스입니다.
Deepak Sharma

이것은 객체를 생성하지 않습니다. 기존 객체에 대한 참조를 할당합니다. 객체는 이미 컴파일러와 클래스 로더에 의해 생성되었습니다.
Lorne의 후작
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.