Tất cả các cách khác nhau để tạo một đối tượng trong Java là gì?


178

Có một cuộc trò chuyện với đồng nghiệp vào ngày khác về điều này.

Rõ ràng là sử dụng một hàm tạo, nhưng những cách khác ở đó là gì?


2
Khi nghi ngờ, hãy nhìn vào thông số ngôn ngữ. 12.5 Tạo các trường hợp lớp mới java.sun.com/docs/books/jls/third_edition/html/ thừng 15.9 Biểu thức tạo lập trường lớp java java.sun.com/docs/books/jls/third_edition/html/ tựa
Bạn bè trên Internet

9
chỉ có 3: c-tor bình thường (từ khóa mới), clone () và Unsafe.allocateInstance(Class). Phần còn lại gọi một trong số đó. Sự phản chiếu được biên dịch thành lệnh gọi c-tor, giải tuần tự hóa thành Unsafe.allocateInstance (Class). Bạn có thể tạo API của riêng mình và cuối cùng bạn sẽ gọi một trong số đó.
bestsss

2
@ bestsss- Unsafelà một chi tiết cụ thể về triển khai của Java và không được đề cập ở bất kỳ đâu trong thông số kỹ thuật. Điều này hoàn toàn có thể xây dựng một thực hiện Java phù hợp mà không sử dụng phản chiếu xuống biên dịch mã mà sử dụng new, clonehoặc Unsafe.allocateInstance.
templatetypedef

2
bạn có thể kiểm tra liên kết, Codeandlogics.com/2017/01/ways-to-create-objects-in-java.html
Pragya

Câu trả lời:


288

Có bốn cách khác nhau để tạo các đối tượng trong java:

Một . Sử dụng newtừ khóa
Đây là cách phổ biến nhất để tạo một đối tượng trong java. Gần 99% các đối tượng được tạo ra theo cách này.

 MyObject object = new MyObject();

B . Sử dụng Class.forName()
Nếu chúng ta biết tên của lớp & nếu nó có một hàm tạo mặc định công khai, chúng ta có thể tạo một đối tượng theo cách này.

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

C . Sử dụng clone()
Clone () có thể được sử dụng để tạo một bản sao của một đối tượng hiện có.

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

D . Sử dụng object deserialization
khử lưu lượng đối tượng không gì khác ngoài việc tạo một đối tượng từ dạng tuần tự hóa của nó.

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

Bạn có thể đọc chúng từ đây .


10
Vì vậy, thực tế chỉ có 2 cách tồn tại: gọi hàm tạo (sử dụng mới, clone () hoặc phản chiếu) và khử lưu huỳnh không gọi hàm tạo.
AlexR

13
@AlexR: Object.clone()cũng không gọi hàm tạo.
axtavt

1
Vì đây có vẻ là câu trả lời ở đầu, bạn có thể thêm các sáng tạo của mảng làm trường hợp con vào A và B không? (Xem câu trả lời của tôi để biết chi tiết).
Paŭlo Ebermann

Deserialisation không gọi một constructor, chỉ không thuộc loại có nguồn gốc nhất.
Tom Hawtin - tackline

2
Bạn cũng nên đề cập đến các Constructorlớp học, mà khái quát Class.newInstance.
templatetypedef

68

Có nhiều cách khác nhau:

  • Thông qua Class.newInstance.
  • Thông qua Constructor.newInstance.
  • Thông qua quá trình khử lưu huỳnh (sử dụng hàm tạo không có đối số của lớp cơ sở không nối tiếp có nguồn gốc nhất).
  • Thông qua Object.clone( không gọi một nhà xây dựng ).
  • Thông qua JNI (nên gọi một nhà xây dựng).
  • Thông qua bất kỳ phương pháp khác mà gọi một newcho bạn.
  • Tôi đoán bạn có thể mô tả tải lớp là tạo các đối tượng mới (chẳng hạn như Strings thực tập ).
  • Một mảng bằng chữ như là một phần của việc khởi tạo trong một khai báo (không có hàm tạo cho mảng).
  • Mảng trong một ...cuộc gọi phương thức "varargs" ( ) (không có hàm tạo cho mảng).
  • Nối chuỗi không đổi thời gian không biên dịch (xảy ra để tạo ra ít nhất bốn đối tượng, trên một triển khai điển hình).
  • Làm cho một ngoại lệ được tạo và ném bởi thời gian chạy. Ví dụ throw null;hoặc "".toCharArray()[0].
  • Oh, và quyền anh của người nguyên thủy (trừ khi được lưu trữ), tất nhiên.
  • JDK8 nên có lambdas (về cơ bản là các lớp bên trong ẩn danh), được chuyển đổi hoàn toàn thành các đối tượng.
  • Để hoàn thiện (và Paŭlo Ebermann), cũng có một số cú pháp với newtừ khóa.

6
Bạn cũng nên thêm "cách thông thường" :-)
Paŭlo Ebermann

@ Paŭlo Ebermann Đó là trường học cũ và không hay. (Tôi giả định rằng câu hỏi có nghĩa là gì khi "sử dụng một hàm tạo (mặc dù hầu hết, nhưng không phải tất cả, ở trên đều sử dụng / một hàm tạo ở đâu đó dọc theo dòng).)
Tom Hawtin - tackline 25/211

thực tế chỉ có 3 cách thực sự để làm điều đó, mà tôi đã thêm nhận xét
bestsss

3
Bạn đã bỏ lỡ một : java.misc.Unsafe.allocateInstance(). Mặc dù đó là khó chịu vì một số lý do. Và trên thực tế, quá trình khử lưu huỳnh không sử dụng hàm tạo không có đối số. Dưới mui xe nó sử dụng allocateInstancehoặc ma thuật đen tương đương.
Stephen C

Câu trả lời hay nhất chưa, nhưng JNI AllocObject().không gọi một nhà xây dựng.
Hầu tước Lorne

25

Trong ngôn ngữ Java, cách duy nhất để tạo một đối tượng là bằng cách gọi hàm tạo của nó, rõ ràng hoặc ngầm định. Sử dụng kết quả phản chiếu trong một cuộc gọi đến phương thức constructor, deserialization sử dụng sự phản chiếu để gọi hàm tạo, các phương thức nhà máy bọc cuộc gọi đến hàm tạo để trừu tượng hóa việc xây dựng thực tế và nhân bản tương tự như một lệnh gọi của hàm tạo.


1
Sai. Deserializatio không gọi hàm tạo của lớp một cách rõ ràng hoặc ngầm định.
Hầu tước Lorne

2
Tôi không nên viết 'hàm tạo của nó' và 'hàm tạo', mà là 'hàm tạo' và 'hàm tạo'. Trong trường hợp khử lưu huỳnh, hàm tạo no-arg áp dụng đầu tiên luôn được gọi.
Nhầm lẫn

1
Việc thực hiện nhân bản mặc định không gọi bất kỳ nhà xây dựng nào.
Didier L

nếu đây là cách thực hiện phương thức nhân bản của tôi "return super.clone ();". Sau đó, nó sẽ không gọi constructor.
Mateen

13

Có, bạn có thể tạo các đối tượng bằng cách sử dụng sự phản chiếu. Ví dụ, String.class.newInstance()sẽ cung cấp cho bạn một đối tượng String trống mới.


1
nếu tôi sử dụng nó, nó yêu cầu tôi đặt trong một khối thử / bắt.
GuruKulki

2
Vâng, có nhiều trường hợp ngoại lệ có thể được ném. Xem JavaDoc cho newInstance () để biết ví dụ về những gì có thể sai.
Thomas Lötzer

11

Có năm cách khác nhau để tạo một đối tượng trong Java,

1. Sử dụng newtừ khóa → constructor được gọi

Employee emp1 = new Employee();

2. Sử dụng newInstance()phương thứcClass → constructor được gọi

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

Nó cũng có thể được viết là

Employee emp2 = Employee.class.newInstance();

3. Sử dụng newInstance()phương thứcConstructor → constructor được gọi

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

4. Sử dụng clone()phương thức → không có lệnh gọi constructor

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

5. Sử dụng khử lưu huỳnh → không có lệnh gọi hàm tạo

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

Ba phương thức đầu tiên newtừ khóa và cả hai đều newInstance()bao gồm một lệnh gọi hàm tạo nhưng sau đó hai phương thức sao chép và giải tuần tự tạo các đối tượng mà không gọi hàm tạo.

Tất cả các phương thức trên đều có mã byte khác nhau được liên kết với chúng, Đọc các cách khác nhau để tạo các đối tượng trong Java với Ví dụ cho các ví dụ và mô tả chi tiết hơn, ví dụ: chuyển đổi mã byte của tất cả các phương thức này.

Tuy nhiên, người ta có thể lập luận rằng việc tạo một đối tượng mảng hoặc chuỗi cũng là một cách tạo đối tượng nhưng những điều này chỉ cụ thể hơn đối với một số lớp và được xử lý trực tiếp bởi JVM, trong khi chúng ta có thể tạo một đối tượng của bất kỳ lớp nào bằng cách sử dụng 5 cách này.


Vui lòng tiết lộ bất kỳ chi nhánh nào và không sử dụng trang web như một cách để quảng bá trang web của bạn thông qua việc đăng bài. Xem Làm thế nào để tôi viết một câu trả lời tốt? .
Yvette - Phục hồi Monica


6

Ngoài ra bạn có thể sử dụng

 Object myObj = Class.forName("your.cClass").newInstance();

6

Điều này cần được chú ý nếu bạn chưa quen với java, mọi đối tượng đều được kế thừa từ Object

Đối tượng bản địa được bảo vệ clone () ném CloneNotSupportedException;


@stacker: Bạn có thể giải thích làm thế nào điều này có liên quan đến việc tạo một đối tượng mới? Cảm ơn.
ryanprayogo

4
@ryanprayogo clone () sẽ trả về một đối tượng mới (mặc dù đối tượng là bản sao của đối tượng mà clone () đã được gọi) và thực sự là cách duy nhất để tạo một đối tượng mới mà không cần gọi hàm tạo.
Thomas Lötzer

6

Ngoài ra, bạn có thể khử tuần tự hóa dữ liệu thành một đối tượng. Điều này không đi qua lớp Xây dựng!


CẬP NHẬT : Cảm ơn Tom đã chỉ ra điều đó trong bình luận của bạn! Và Michael cũng đã thử nghiệm.

Nó đi qua các hàm tạo của siêu lớp không tuần tự có nguồn gốc nhất.
Và khi lớp đó không có hàm tạo không có đối số, một UnlimitedClassException sẽ bị loại bỏ khi xê-ri hóa.

Vui lòng xem câu trả lời của Tom để xử lý hoàn toàn tất cả các trường hợp ;-)
có cách nào khác để tạo đối tượng mà không sử dụng từ khóa "mới" trong java không


1
Nó đi qua một hàm tạo (hàm tạo không có đối số của siêu lớp không nối tiếp có nguồn gốc nhất).
Tom Hawtin - tackline

1
@Tom Oh wow - Tôi không biết điều đó và đã thử nghiệm một chút. Rõ ràng là khi siêu lớp không tuần tự có nguồn gốc nhất không có hàm tạo không có đối số, nó sẽ dẫn đến một UnlimitedClassException được nối tiếp vào luồng và được ném vào quá trình khử lưu huỳnh !! - Sao mà kỳ quái thế?
Michael Borgwardt

6

Có một loại đối tượng, không thể được xây dựng bằng các cơ chế tạo cá thể thông thường (gọi các hàm tạo): Mảng . Mảng được tạo ra với

 A[] array = new A[len];

hoặc là

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

Như Sean đã nói trong một nhận xét, điều này về mặt cú pháp tương tự như một lệnh gọi của hàm tạo và bên trong nó không khác gì nhiều so với phân bổ và khởi tạo bằng không (hoặc khởi tạo với nội dung rõ ràng, trong trường hợp thứ hai) một khối bộ nhớ, với một số tiêu đề để chỉ ra loại và chiều dài.

Khi truyền các đối số cho một phương thức varargs, một mảng cũng được tạo (và điền) hoàn toàn.

Cách thứ tư sẽ là

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

Tất nhiên, nhân bản và khử lưu huỳnh cũng hoạt động ở đây.

Có nhiều phương thức trong API tiêu chuẩn tạo ra các mảng, nhưng thực tế tất cả chúng đều sử dụng một (hoặc nhiều) các cách này.


Cấp, bạn không thể định nghĩa các hàm tạo Array, nhưng ngoài ra cơ chế đó là cùng một newtừ khóa. Array.newInstance là cơ chế mới duy nhất ở đây
Sean Patrick Floyd

@Sean: Đó là cùng một từ khóa, nhưng tôi dám nói là một cơ chế nội bộ khá khác biệt.
Paŭlo Ebermann

Điều đó đúng, tất nhiên. Nhưng mặt khác, các phiên bản khác nhau của việc tạo mảng là bên trong khá giống nhau. Chỉ cần nhận ra câu trả lời của bạn là từ năm 2011. Xin lỗi vì đã khuấy động những thứ cũ :-)
Sean Patrick Floyd

@Sean: Không có vấn đề gì, tôi đã sử dụng dịp này để thực hiện một số sửa lỗi ngữ pháp.
Paŭlo Ebermann

công việc tốt, không ai thảo luận ở đây về mảng!
Mateen

5

Những cách khác nếu chúng ta đang bị cạn kiệt.

  • Trên Oracle JVM là Unsafe.allocateInstance () tạo ra một cá thể mà không cần gọi hàm tạo.
  • Sử dụng mã byte thao tác bạn có thể thêm mã để anewarray, multianewarray, newarrayhoặc new. Chúng có thể được thêm bằng các thư viện như ASM hoặc BCEL. Một phiên bản của bcel được vận chuyển với Java của Oracle. Một lần nữa, điều này không gọi hàm tạo, nhưng bạn có thể gọi hàm tạo như một cuộc gọi riêng.


4

Phản ánh cũng sẽ làm công việc cho bạn.

SomeClass anObj = SomeClass.class.newInstance();

là một cách khác để tạo một thể hiện mới của một lớp. Trong trường hợp này, bạn cũng sẽ cần xử lý các trường hợp ngoại lệ có thể bị ném.


4
  • sử dụng newtoán tử (do đó gọi hàm tạo)
  • sử dụng sự phản chiếu clazz.newInstance()(một lần nữa gọi hàm tạo). Hoặc bằng cách clazz.getConstructor(..).newInstance(..)(một lần nữa sử dụng hàm tạo, nhưng do đó bạn có thể chọn cái nào)

Để tóm tắt câu trả lời - một cách chính - bằng cách gọi hàm tạo của lớp đối tượng.

Cập nhật: Một câu trả lời khác liệt kê hai cách không liên quan đến việc sử dụng một hàm tạo - khử lưu huỳnh và nhân bản.


4

Có nhiều cách khác nhau để tạo các đối tượng trong Java:

1. Sử dụng từ khóa `new`:

Đây là cách phổ biến nhất để tạo một đối tượng trong Java. Gần 99% các đối tượng được tạo ra theo cách này.

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

2. Bằng cách sử dụng phương pháp nhà máy:

ClassName ObgRef=ClassName.FactoryMethod();

Thí dụ:

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

3. Bằng cách sử dụng khái niệm nhân bản:

Bằng cách sử dụng clone(), clone()có thể được sử dụng để tạo một bản sao của một đối tượng hiện có.

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

4. Sử dụng `Class.forName ()`:

Nếu chúng ta biết tên của lớp & nếu nó có một hàm tạo mặc định công khai, chúng ta có thể tạo một đối tượng theo cách này.

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

Thí dụ:

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

5. Sử dụng khử lưu huỳnh đối tượng:

Đối tượng khử lưu huỳnh không là gì ngoài việc tạo một đối tượng từ dạng tuần tự của nó.

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

(4) chỉ yêu cầu Class.forName()nếu bạn chưa có lớp, trong tất cả các trường hợp khác bạn làm. Nó cũng không yêu cầu một hàm tạo không có đối số: có nhiều cách để gọi bất kỳ hàm tạo công khai nào nếu bạn biết các đối số chính xác. Và bạn đã bỏ qua ít nhất hai cách khác.
Hầu tước Lorne

2
(2) Phương thức Factory chỉ là một mẫu để lấy các đối tượng. Nhưng bên trong nó sử dụng từ khóa "mới" để tạo đối tượng.
Karthik Bose

Tại sao nhiều người nói phương pháp nhà máy tạo ra các đối tượng, các bạn đã học điều này từ đâu?
Mateen

3

Bạn cũng có thể sao chép đối tượng hiện có (nếu nó thực hiện Clonizable).

Foo fooClone = fooOriginal.clone (); 

2

Phương pháp 1

Sử dụng từ khóa mới. Đây là cách phổ biến nhất để tạo một đối tượng trong java. Gần 99% các đối tượng được tạo ra theo cách này.

Employee object = new Employee();

Cách 2

Sử dụng Class.forName (). Class.forName () cung cấp cho bạn đối tượng lớp, rất hữu ích cho việc phản chiếu. Các phương thức mà đối tượng này đã được xác định bởi Java, không phải bởi lập trình viên viết lớp. Chúng giống nhau cho mọi lớp học. Gọi newInstance () trên đó cung cấp cho bạn một thể hiện của lớp đó (tức là gọiClass.forName ("exampleClass"). NewInstance () tương đương với việc gọi newClassClass ()), trên đó bạn có thể gọi các phương thức mà lớp định nghĩa, truy cập vào các lĩnh vực có thể nhìn thấy, vv

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

Class.forName () sẽ luôn sử dụng ClassLoader của người gọi, trong khi ClassLoader.loadClass () có thể chỉ định một ClassLoader khác. Tôi tin rằng Class.forName cũng khởi tạo lớp được tải, trong khi cách tiếp cận ClassLoader.loadClass () không làm điều đó ngay lập tức (nó không được khởi tạo cho đến khi nó được sử dụng lần đầu tiên).

Một cái khác phải đọc:

Java: Giới thiệu trạng thái luồng với ví dụ Ví dụ đơn giản Java Enum

Phương pháp 3

Sử dụng bản sao (). Clone () có thể được sử dụng để tạo một bản sao của một đối tượng hiện có.

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

Phương pháp 4

Sử dụng phương thức newInstance ()

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

Phương pháp 5

Sử dụng Object Deserialization. Object Deserialization không gì khác ngoài việc tạo một đối tượng từ dạng tuần tự của nó.

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

Không sử dụng định dạng mã cho văn bản không phải là mã. Có nhiều phương pháp hơn những phương pháp này. Đọc các câu trả lời khác. "Gần 99%" chỉ là phỏng đoán.
Hầu tước Lorne

Hi EJP xin lỗi vì sai lầm này ... Tôi biết đây là một loại cách để tạo ra các đối tượng không nói chính xác one.Its quyền của mình chỉ là một model..and xin lỗi am alearner và cái mới để stackoverflow
Andriya

0

Từ góc độ người dùng API, một phương án khác cho các nhà xây dựng là các phương thức nhà máy tĩnh (như BigInteger.valueOf ()), mặc dù đối với tác giả API (và về mặt kỹ thuật "thực tế"), các đối tượng vẫn được tạo bằng cách sử dụng hàm tạo.


-1

Phụ thuộc chính xác những gì bạn có nghĩa là bằng cách tạo nhưng một số khác là:

  • Phương pháp nhân bản
  • Khử muối
  • Phản ánh (Class.newInstance ())
  • Phản xạ (đối tượng xây dựng)

2
3 và 4 là các bí danh khác nhau cho cùng một cơ chế
Sean Patrick Floyd

-2

cũng có ClassLoader.loadClass (chuỗi) nhưng điều này không thường được sử dụng.

và nếu bạn muốn trở thành một luật sư toàn diện về nó, các mảng là các đối tượng kỹ thuật vì thuộc tính .length của một mảng. vì vậy việc khởi tạo một mảng tạo ra một đối tượng.


1
loadClass (Tên chuỗi) trả về kết quả Đối tượng lớp mà một đối tượng có Nhưng không phải đối tượng của lớp đó. Nếu các ví dụ được đưa ra thì chúng ta có thể tìm thấy rất nhiều ví dụ như vậy trong thư viện java nhưng chúng sẽ là các lớp cụ thể. kiểm tra youtu.be/gGGCmrD6Qpw
nanosoft

-3

Chúng ta có thể tạo một đối tượng theo 5 cách:

  1. bởi nhà điều hành mới
  2. bằng phản xạ (ví dụ Class.forName () theo sau là Class.newInstance ())
  3. theo phương pháp nhà máy
  4. bằng cách nhân bản
  5. bằng phản xạ api

3
Class.forName () tải một lớp thay vì tạo một đối tượng.
Hầu tước Lorne

Phản xạ? Chắc chắn bạn có nghĩa là sự phản ánh.
Stephen C

Làm thế nào bạn có thể tạo đối tượng từ phương thức nhà máy, thực hiện nội bộ có thể được sử dụng lại từ khóa mới phải không? và tại sao bạn có phản xạ hai lần? Sẽ có ý nghĩa hơn nếu bạn thực sự đưa ra một số bài kiểm tra
Mateen

-5

Chúng ta cũng có thể tạo đối tượng theo cách này: -

String s ="Hello";

Không ai đã thảo luận về nó.


Đây là cách tạo ra các kiểu dữ liệu nguyên thủy, nó chỉ là một sự linh hoạt mà Java cung cấp đằng sau hậu trường để không sử dụng từ khóa "mới". Điều này giống như từ khóa mới.
Madusudanan

Madhusudan, FYI, Với sự trợ giúp của nhà điều hành mới, các đối tượng sẽ luôn lưu trữ thành từng đống trong khi trong trường hợp này "Xin chào" là một đối tượng nên lưu trữ trong chuỗi String. Và String là một lớp không phải là kiểu dữ liệu nguyên thủy.
Deepak Sharma

Điều này không tạo ra một đối tượng. Nó gán một tham chiếu cho một đối tượng hiện có. Đối tượng đã được tạo bởi trình biên dịch và trình nạp lớp.
Hầu tước Lorne
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.