Có cách nào để khởi tạo một lớp theo tên trong Java không?


102

Tôi đang xem như câu hỏi: Khởi tạo một lớp từ tên chuỗi của nó , mô tả cách khởi tạo một lớp khi có tên của nó. Có cách nào để làm điều đó trong Java không? Tôi sẽ có tên gói và tên lớp và tôi cần có thể tạo một đối tượng có tên cụ thể đó.


Chúng tôi khởi tạo một lớp và kết quả là một đối tượng (hoặc: thể hiện ).
Andreas Dolk

1
Câu trả lời là có, nhưng tôi nghĩ rằng bạn nên tự hỏi nếu ý tưởng tốt của nó. Với sức mạnh to lớn (phản chiếu) đi kèm với trách nhiệm lớn và bạn chỉ nên sử dụng nó nếu bạn hiểu và đã cân nhắc hậu quả.
c1moore

Câu trả lời:


238

Hai lối:

Phương pháp 1 - chỉ dành cho các lớp có hàm tạo no-đối số

Nếu lớp của bạn có hàm tạo no-arg, bạn có thể lấy một Classđối tượng bằng cách sử dụng Class.forName()và sử dụng newInstance()phương thức này để tạo một thể hiện (mặc dù hãy cẩn thận rằng phương thức này thường bị coi là xấu vì nó có thể đánh bại các ngoại lệ đã được kiểm tra của Java).

Ví dụ:

Class<?> clazz = Class.forName("java.util.Date");
Object date = clazz.newInstance();

Phương pháp 2

Một cách tiếp cận khác an toàn hơn cũng hoạt động nếu lớp không có bất kỳ hàm tạo no-arg nào là truy vấn đối tượng lớp của bạn để lấy Constructorđối tượng của nó và gọi một newInstance()phương thức trên đối tượng này:

Class<?> clazz = Class.forName("com.foo.MyClass");
Constructor<?> constructor = clazz.getConstructor(String.class, Integer.class);
Object instance = constructor.newInstance("stringparam", 42);

Cả hai phương pháp được gọi là phản xạ . Bạn thường sẽ phải nắm bắt các ngoại lệ khác nhau có thể xảy ra, bao gồm những thứ như:

  • JVM không thể tìm thấy hoặc không thể tải lớp của bạn
  • lớp bạn đang cố gắng khởi tạo không có đúng loại hàm tạo
  • chính hàm tạo đã ném một ngoại lệ
  • hàm tạo bạn đang cố gọi không công khai
  • một trình quản lý bảo mật đã được cài đặt và đang ngăn phản ánh xảy ra

xin chào, khi chúng ta đã tạo đối tượng từ đó newInstance(), chúng ta có thể truyền nó trở lại đối tượng của chính mình không?
GMsoF

@Simon, bạn có thể giải thích / cho ý kiến ​​về trình quản lý bảo mật không?
Ram

Tôi không hiểu điều này. Tôi muốn truy cập một lớp trong một tệp không xác định trong một số thư mục khác, tôi chỉ có tên của đường dẫn / tệp dưới dạng một chuỗi. Chuỗi "dir / unaonwn.java". Việc gọi Class.forName ("dir / chưa biết") gây ra lỗi cho tôi.
john ktejik

Làm thế nào chúng ta có thể truyền instanceđến com.foo.MyClass? cho rằng com.foo.MyClass chỉ là một chuỗi
Sanket9394

14
MyClass myInstance = (MyClass) Class.forName("MyClass").newInstance();

15
Điều đáng nói là điều này không hoạt động nếu lớp không có hàm tạo không tham số (và có các hàm tạo khác), hoặc nếu hàm tạo không tham số không thể truy cập được.
Dawood ibn Kareem

3

use Class.forName ("Tên chuỗi của lớp"). newInstance ();

Class.forName("A").newInstance();

Điều này sẽ làm cho lớp có tên A được khởi tạo.


Nó không hoạt động với tôi, ngay cả với tên gói được viết sẵn. :(
trusktr

3

Để dễ dàng lấy được tên đủ điều kiện của một lớp để tạo một thể hiện bằng cách sử dụng Class.forName(...), người ta có thể sử dụng Class.getName()phương thức này. Cái gì đó như:

class ObjectMaker {
    // Constructor, fields, initialization, etc...
    public Object makeObject(Class<?> clazz) {
        Object o = null;

        try {
            o = Class.forName(clazz.getName()).newInstance();
        } catch (ClassNotFoundException e) {
            // There may be other exceptions to throw here, 
            // but I'm writing this from memory.
            e.printStackTrace();
        }

        return o;
    }
}

Sau đó, bạn có thể truyền đối tượng mà bạn quay lại bất kỳ lớp nào mà bạn chuyển đến makeObject(...):

Data d = (Data) objectMaker.makeObject(Data.class);

1
Bạn không thể đơn giản clazz.newInstance()thay vì getNamesau đó fromName?
user276648 14/12/16

1

Sử dụng phản chiếu java

Tạo đối tượng mới Không có gì tương đương với việc gọi phương thức cho các hàm tạo, bởi vì việc gọi một hàm tạo tương đương với việc tạo một đối tượng mới (chính xác nhất, việc tạo một đối tượng mới bao gồm cả cấp phát bộ nhớ và xây dựng đối tượng). Vì vậy, tương đương gần nhất với ví dụ trước là nói:

import java.lang.reflect.*;

   public class constructor2 {
      public constructor2()
      {
      }

      public constructor2(int a, int b)
      {
         System.out.println(
           "a = " + a + " b = " + b);
      }

      public static void main(String args[])
      {
         try {
           Class cls = Class.forName("constructor2");
           Class partypes[] = new Class[2];
            partypes[0] = Integer.TYPE;
            partypes[1] = Integer.TYPE;
            Constructor ct 
              = cls.getConstructor(partypes);
            Object arglist[] = new Object[2];
            arglist[0] = new Integer(37);
            arglist[1] = new Integer(47);
            Object retobj = ct.newInstance(arglist);
         }
         catch (Throwable e) {
            System.err.println(e);
         }
      }
   }

tìm một phương thức khởi tạo xử lý các kiểu tham số đã chỉ định và gọi nó, để tạo một thể hiện mới của đối tượng. Giá trị của cách tiếp cận này là nó hoàn toàn động, với việc tra cứu hàm tạo và gọi vào thời điểm thực thi, thay vì lúc biên dịch.



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

0

một cái gì đó như thế này sẽ hoạt động ...

String name = "Test2";//Name of the class
        Class myClass = Class.forName(name);
        Object o = myClass.newInstance();

0

Sử dụng newInstance()trực tiếp không được chấp nhận kể từ Java 8. Bạn cần sử dụng Class.getDeclaredConstructor(...).newInstance(...)với các ngoại lệ tương ứng.

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.