Trong ngôn ngữ Java, để khởi tạo một instance của một class, chúng ta thường sử dụng từ khóa "new". Tuy nhiên, có những trường hợp đặc biệt mà chúng ta cần tạo instance mà không biết trước tên class, constructor là private, hoặc không biết được số lượng tham số của constructor. Trong bài viết này, chúng ta sẽ tìm hiểu các cách giải quyết vấn đề này.
Sử dụng kỹ thuật Reflection
Một trong những cách đơn giản và phổ biến để tạo instance của một class là sử dụng kỹ thuật Reflection. Kỹ thuật này cho phép chúng ta tạo instance dựa trên tên class và các thông tin về constructor của class đó.
Class<?> clazz = Class.forName("com.gpcoder.instance.Employee");
Employee employee = (Employee) clazz.newInstance();
employee.setId(1);
employee.setName("gpcoder");
Lưu ý: Nếu không tồn tại constructor không có tham số, chương trình sẽ gây ra exception.
Sử dụng phương thức getConstructor()
Một cách khác để tạo instance của class là sử dụng phương thức getConstructor()
, đặc biệt khi constructor của class là public. Chúng ta có thể lấy tất cả các constructor của class và tạo instance dựa trên từng constructor.
Class<?> clazz = Class.forName("com.gpcoder.instance.Employee");
Constructor<?>[] allConstructors = clazz.getConstructors();
for (Constructor<?> constructor : allConstructors) {
Class<?>[] parameters = constructor.getParameterTypes();
if (parameters.length == 0) {
Employee employee1 = (Employee) constructor.newInstance();
employee1.setId(1);
employee1.setName("gpcoder 1");
System.out.println("employee1: " + employee1);
} else if (parameters.length == 2) {
Employee employee2 = (Employee) constructor.newInstance(2, "gpcoder 2");
System.out.println("employee2: " + employee2);
}
}
Constructor<?> constructor = clazz.getConstructor(int.class, String.class);
Employee employee3 = (Employee) constructor.newInstance(3, "gpcoder 3");
System.out.println("employee3: " + employee3);
Sử dụng phương thức getDeclaredConstructor()
Nếu constructor của class là private, chúng ta không thể tạo instance thông qua phương thức getConstructor()
. Thay vào đó, chúng ta có thể sử dụng phương thức getDeclaredConstructor()
và đặt quyền truy cập là public để tạo instance.
Class<?> clazz = Class.forName("com.gpcoder.instance.PrivateEmployee");
Constructor<?> constructor = clazz.getDeclaredConstructor(int.class, String.class);
constructor.setAccessible(true);
PrivateEmployee employee = (PrivateEmployee) constructor.newInstance(1, "gpcoder");
System.out.println("employee: " + employee);
Sử dụng Objenesis
Các cách trên có những hạn chế như yêu cầu constructor không có tham số, không thể xác định chính xác số lượng tham số của constructor, hoặc chúng ta không thể gọi trực tiếp constructor. Để khắc phục những hạn chế này, 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, được sử dụng để tạo instance của một class mà không thông qua constructor. Điều này giúp chúng ta tạo instance dễ dàng hơn mà không cần quan tâm đến constructor.
Objenesis objenesis = new ObjenesisStd();
Class<?> clazz = Class.forName("com.gpcoder.instance.ProductFactory");
ObjectInstantiator<?> instantiator = objenesis.getInstantiatorOf(clazz);
ProductFactory productFactory1 = (ProductFactory) instantiator.newInstance();
ProductFactory productFactory2 = (ProductFactory) instantiator.newInstance();
ProductFactory productFactory3 = (ProductFactory) instantiator.newInstance();
System.out.println("productFactory1: " + productFactory1);
System.out.println("productFactory2: " + productFactory2);
System.out.println("productFactory3: " + productFactory3);
productFactory1.doSomething("factory1");
productFactory2.doSomething("factory2");
productFactory3.doSomething("factory3");
Lưu ý: Do Objenesis tạo instance không thông qua constructor, 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ó.
Kết
Trong bài viết này, chúng ta đã tìm hiểu cách tạo instance của một class mà không cần gọi từ khóa "new" thông qua kỹ thuật Reflection và sử dụng thư viện Objenesis. Việc biết cách tạo instance một cách linh hoạt sẽ giúp chúng ta trong việc xử lý các trường hợp đặc biệt và tăng tính linh hoạt của chương trình.
Link bài viết gốc: Làm thế nào tạo instance của một class mà không gọi từ khóa new?