Làm thế nào tạo instance của một class mà không gọi từ khóa new?

1724
tạo instance của class trong java

Như đã biết, để khởi tạo instance của class trong Java chúng ta sẽ sử dụng từ khóa new. Tuy nhiên, trong một số trường hợp chúng ta cần tạo một instance khi chỉ biết tên class hoặc private constructor hoặc không biết được số lượng tham số của constructor… Với những trường hợp như vậy, chúng ta không thể gọi từ khóa new một cách trực tiếp mà sẽ sử dụng một số cách đặc biệt và chúng ta sẽ cùng tìm hiểu các cách giải quyết vấn đề này trong phần tiếp theo của bài viết.

Sử dụng Reflection khi biết tên class

Một trong những cách đơn giản và thường được sử dụng để tạo instance của một class là sử dụng kỹ thuật Reflection.

Sử dụng newInstance() khi class có constructor không có tham số và phạm vi truy cập không phải private

Tạo instance sử dụng newInstance():

Lưu ý:

Nếu không tồn tại constructor không có tham số, chương trình sẽ throw ra một exception như sau:

Nếu constructor không tham số có phạm vi truy cập là private, chương trình sẽ throw ra exception sau:

Sử dụng getConstructor() khi constructor của class là public

Chúng ta sẽ tạo instance của class Employee sử dụng phương thức getConstructor():

Output của chương trình:

Sử dụng getDeclaredConstructor() khi constructor của class là private

Sử dụng getDeclaredConstructor() khi các constructor của class là private:

Output của chương trình:

  Top 10 câu hỏi phỏng vấn Java thường gặp
  10 Java Web Framework tốt nhất

Sử dụng Object.clone() để tạo một instance từ một instance khác

Để sử dụng phương thức clone(), class cần implement interface java.lang.Cloneable và override phương thức clone(). Chi tiết các bạn xem lại bài viết Object cloning trong java.

Tạo new instance từ clone():

Output chương trình:

Tạo new instance sử dụng serialization và deserialization

Chúng ta có thể tạo một instance cho một class bằng cách sử dụng Deserialization từ một data object đã được Serialization. Khi sử dụng deserialization, JVM sẽ không sử dụng bất kỳ constructor nào để tạo instance. Chi tiết các bạn xem lại bài viết Serialization và Deserialization trong java.

Giả sử chúng ta cần tạo instance cho class sau:

Bây giờ chúng ta sẽ tạo một đối tượng đã được Serialize và lưu vào một nơi nào đó (có thể lưu trữ ở một nơi nào đó tách biệt hoặc nhận từ một service khác). Sau đó, chúng ta đọc file này và tạo instance sử dụng Deserialize.

Output chương trình:

Sử dụng thư viện Objenesis

Objenesis là gì?

Một số hạn chế của các cách ở trên:

  • Với phương thức Class.newInstance(), class của chúng ta bắt buộc phải có constructor không có tham số.
  • Với Class.getDeclaredConstructor() hoặc Class.getConstructor(), chúng ta phải xác định chính xác số lượng tham số và kiểu dữ liệu của từng tham số.
  • Với Object.clone(), class của chúng ta phải implement một interface Clonable.
  • Với serialization và deserialization, class của chúng ta phải implement một interface Serializable.

Ngoài ra, một số trường hợp chúng ta có thể gặp phải khi tạo instance thông qua constructor như:

  • Trong constructor có throw exception, chẳng hạn private constructor của singleton hay util class có thể throw exception trực tiếp trong constructor.
  • Trong constructor gọi rất nhiều xử lý khác, nó làm chậm quá trình khởi tạo instance và chúng ta cũng không cần dữ liệu khởi tạo đó.

Để có thể tạo một instance cho một class mà không gặp bất kỳ hạn chế trên, chúng ta có thể sử dụng thư viện Objenesis. Objenesis là một thư viện mã nguồn mở của Java, nó được sử dụng để tạo instance của một class đặc biệt mà không thông qua constructor.

Cài đặt Objenesis

Thêm thư viện Objenesis vào project vào project maven:

Ví dụ sử dụng Objenesis

Giả sử chúng ta có một class có constructor là private và trong constructor này có throw một exception.

Như bạn thấy, với những cách đã giới thiệu ở trên chúng ta không thể khởi tạo được instance của class này. Bây giờ hãy xem cách sử dụng Objenesis:

Output của chương trình:

Lưu ý: Do Objenesis khởi tạo đối tượng không thông qua constructor nên các giá trị khởi tạo trong constructor sẽ không tồn tại. Do đó, chúng ta cần gán lại các giá trị cho đối tượng trước khi gọi các phương thức của nó.

Ví dụ chúng ta có một class Document. Class này ban đầu chỉ chứa thông tin về document. Sau đó, hệ thống cần xuất dữ liệu document ra file và mỗi loại document có cách xuất dữ liệu/ biểu mẫu khác nhau. Do đó, chúng ta thêm một field className để lưu thông tin tên concrete class. Chúng ta có cấu trúc như sau:

Code chương trình:

Document.java

SelfDocumentGenerable.java

Concrete1SelfDocumentGenerable.java

Concrete2SelfDocumentGenerable.java

Như bạn thấy, mỗi concrete class có constructor với các tham số khác nhau, chúng ta không thể gọi từ khóa new một cách trực tiếp, không thể gọi phương thức newInstance() do không chắc chắn các concrete class có constructor không tham số hay không và cũng không thể xác định chính xác các tham số của constructor nên không thể sử dụng getConstructor(). Trường hợp này, chúng ta sẽ sử dụng Objenesis để tạo instance.

Do Objenesis tạo instance không thông qua constructor nên chúng ta phải gán lại các giá trị title và author cho phương thức generateFile() sử dụng.

DocumentGenerator.java

ObjenesisDocumentGeneratorExample.java

Output của chương trình:

Link bài viết gốc: https://gpcoder.com/5525-lam-the-nao-tao-instance-cua-mot-class-ma-khong-goi-tu-khoa-new/