Tạo một cá thể bằng cách sử dụng tên lớp và hàm tạo


312

Có cách nào để tạo một thể hiện của một lớp cụ thể với tên lớp (động) và truyền tham số cho hàm tạo của nó không.

Cái gì đó như:

Object object = createInstance("mypackage.MyClass","MyAttributeValue");

Trường hợp "MyAttributeValue"là một đối số cho các nhà xây dựng của MyClass.

Câu trả lời:


497

Vâng, đại loại như:

Class<?> clazz = Class.forName(className);
Constructor<?> ctor = clazz.getConstructor(String.class);
Object object = ctor.newInstance(new Object[] { ctorArgument });

Điều đó sẽ chỉ hoạt động cho một tham số chuỗi duy nhất, nhưng bạn có thể sửa đổi nó khá dễ dàng.

Lưu ý rằng tên lớp phải là một tên đủ điều kiện, nghĩa là bao gồm cả không gian tên. Đối với các lớp lồng nhau, bạn cần sử dụng một đô la (như đó là những gì trình biên dịch sử dụng). Ví dụ:

package foo;

public class Outer
{
    public static class Nested {}
}

Để có được Classđối tượng cho điều đó, bạn cần Class.forName("foo.Outer$Nested").


5
newInstance()là một phương thức varargs (giống như GetConstructor()), không cần Objecttạo -array rõ ràng .
Joachim Sauer

18
@Joachim: Tôi biết đó là các biến thể, nhưng vì nó có thể trở nên khó khăn khi bạn có một Object[]đối số, tôi thích tạo ra mảng rõ ràng trong trường hợp này.
Jon Skeet

2
clazz.getConstructor (String. class); Tại sao String. class ở đây?
Umair A.

2
@Neutralizer: Có, nhưng tôi đã trả lời một câu hỏi không cần phải năng động.
Jon Skeet

3
@JonSkeet Tôi hiểu bạn đến từ đâu, tuy nhiên nó không đơn giản lắm - tôi đã xem các tài liệu nhưng bối rối, nhưng nếu tôi đã thử nó và nó hoạt động - ok thì nó vẫn hoạt động - nhưng nếu nó không hoạt động Tôi đã không chắc chắn nếu vấn đề là do một số thiếu cấu hình hoặc một cái gì đó về phía tôi - thường khi hỏi những câu hỏi đơn giản như vậy, mọi người ném vào các mẩu tin hữu ích thực sự có ích. Đó là lý do tại sao một "đơn giản sẽ có hiệu quả - nếu bạn làm theo cách này" hoặc "không có cách nào", thực sự hữu ích. Nhưng sự hiểu biết của tôi bây giờ là không có cách nào
ycomp

97

Bạn có thể sử dụng Class.forName()để có được một Classđối tượng của lớp mong muốn.

Sau đó sử dụng getConstructor()để tìm Constructorđối tượng mong muốn .

Cuối cùng, gọi newInstance()đối tượng đó để lấy ví dụ mới của bạn.

Class<?> c = Class.forName("mypackage.MyClass");
Constructor<?> cons = c.getConstructor(String.class);
Object object = cons.newInstance("MyAttributeValue");

81

Bạn có thể sử dụng phản xạ

return Class.forName(className).getConstructor(String.class).newInstance(arg);

3
Nếu sử dụng hàm tạo mặc định, hãy xóa giá trị tham số String. Class, ví dụ trả về Class.forName (className) .getConstructor (). NewInstance (arg);
Vijay Kumar

21
@VijayKumar Tôi nghĩ bạn có ý đó Class.forName(className).getConstructor().newInstance();;)
Peter Lawrey

14

Nếu lớp chỉ có một hàm tạo trống (như Activity hoặc Fragment, v.v., các lớp android):

Class<?> myClass = Class.forName("com.example.MyClass");    
Constructor<?> constructor = myClass.getConstructors()[0];

2
Đây là những gì đã giúp tôi. Constructor<?> ctor = clazz.getConstructor(String.class)dường như không làm việc cho tôi.
Leo C Han

8

khi sử dụng (tức là) getConstructor(String.lang)hàm tạo phải được khai báo công khai. Nếu không thì a NoSuchMethodExceptionbị ném.

nếu bạn muốn truy cập một nhà xây dựng ngoài công cộng, bạn phải sử dụng thay thế (tức là) getDeclaredConstructor(String.lang).



4

Cách rất đơn giản để tạo một đối tượng trong Java bằng cách sử dụng Class<?>(các) đối số hàm tạo:

Trường hợp 1: - Đây là một mã nhỏ trong Mainlớp này :

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Main {

    public static void main(String args[]) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

        // Get class name as string.
        String myClassName = Base.class.getName();
        // Create class of type Base.
        Class<?> myClass = Class.forName(myClassName);
        // Create constructor call with argument types.
        Constructor<?> ctr = myClass.getConstructor(String.class);
        // Finally create object of type Base and pass data to constructor.
        String arg1 = "My User Data";
        Object object = ctr.newInstance(new Object[] { arg1 });
        // Type-cast and access the data from class Base.
        Base base = (Base)object;
        System.out.println(base.data);
    }

}

Và, đây là Basecấu trúc lớp:

public class Base {

    public String data = null;

    public Base() 
    {
        data = "default";
        System.out.println("Base()");
    }

    public Base(String arg1) {
        data = arg1;
        System.out.println("Base("+arg1+")");
    }

}

Trường hợp 2: - Bạn, có thể mã tương tự cho hàm tạo với nhiều đối số và sao chép hàm tạo. Ví dụ, truyền 3 đối số làm tham số cho hàm Basetạo sẽ cần hàm tạo được tạo trong lớp và thay đổi mã ở trên như:

Constructor<?> ctr = myClass.getConstructor(String.class, String.class, String.class);
Object object = ctr.newInstance(new Object[] { "Arg1", "Arg2", "Arg3" }); 

Và ở đây, lớp Base bằng cách nào đó trông giống như:

public class Base {

    public Base(String a, String b, String c){
        // This constructor need to be created in this case.
    }   
}

Lưu ý: - Đừng quên xử lý các ngoại lệ khác nhau cần xử lý trong mã.


Một cách khác cũng là bằng cách sao chép () đối tượng java hiện có. Điều này tạo ra một bản sao của một đối tượng Java hiện có. Trong trường hợp này, bạn cũng phải xử lý khái niệm sao chép Deep hoặc Shallow.
Rahul Raina

2

Nếu bất cứ ai đang tìm kiếm một cách để tạo một thể hiện của một lớp mặc dù lớp đó theo Mẫu Singleton, đây là một cách để làm điều đó.

// Get Class instance
Class<?> clazz = Class.forName("myPackage.MyClass");

// Get the private constructor.
Constructor<?> cons = clazz.getDeclaredConstructor();

// Since it is private, make it accessible.
cons.setAccessible(true);

// Create new object. 
Object obj = cons.newInstance();

Điều này chỉ hoạt động cho các lớp thực hiện mẫu singleton bằng cách sử dụng một hàm tạo riêng.


1

Bạn cũng có thể gọi các phương thức bên trong đối tượng được tạo.

Bạn có thể tạo đối tượng ngay lập tức bằng cách gọi công cụ đầu tiên và sau đó gọi phương thức đầu tiên trong đối tượng được tạo.

    Class<?> c = Class.forName("mypackage.MyClass");
    Constructor<?> ctor = c.getConstructors()[0];
    Object object=ctor.newInstance(new Object[]{"ContstractorArgs"});
    c.getDeclaredMethods()[0].invoke(object,Object... MethodArgs);

Làm thế nào bạn sẽ biết rằng hàm tạo đầu tiên lấy Stringtham số? Trở nên hơi lộn xộn khi bạn thay đổi thứ tự xây dựng
Farid

@Farid từ tài liệu lớp học
Badawi

Vẫn còn getConstructor(ClassName.class)tốt hơn, tôi đoán. Ngay cả khi thứ tự của các nhà xây dựng thay đổi trong lớp, không cần phải tìm vị trí theo cách thủ công
Farid

@Farid - c.getDeclaredMethods () [0] .invoke (object, Object ... MethodArss); chỉ định hàm tạo đặc biệt trong một số trường hợp bạn có thể cần cái này, nhưng bạn đã đúng.
HHR Badawi

1

Một câu trả lời hữu ích khác. Làm cách nào để sử dụng getConstructor (params) .newInstance (args)?

return Class.forName(**complete classname**)
    .getConstructor(**here pass parameters passed in constructor**)
    .newInstance(**here pass arguments**);

Trong trường hợp của tôi, hàm tạo của lớp tôi lấy Webdo làm tham số, do đó được sử dụng dưới đây mã:

return Class.forName("com.page.BillablePage")
    .getConstructor(WebDriver.class)
    .newInstance(this.driver);
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.