มีวิธีสร้างอินสแตนซ์คลาสตามชื่อใน Java หรือไม่?


103

ฉันกำลังมองหาคำถาม: สร้างอินสแตนซ์คลาสจากชื่อสตริงซึ่งอธิบายถึงวิธีการสร้างอินสแตนซ์คลาสเมื่อมีชื่อ มีวิธีทำใน Java ไหม? ฉันจะมีชื่อแพ็กเกจและชื่อคลาสและฉันต้องสามารถสร้างอ็อบเจกต์ที่มีชื่อเฉพาะนั้นได้


เรายกตัวอย่างระดับและผลที่เป็นวัตถุ (หรือ: อินสแตนซ์ )
Andreas Dolk

1
คำตอบคือใช่ แต่ฉันคิดว่าคุณควรถามว่าเป็นความคิดที่ดีหรือไม่ ด้วยพลังอันยิ่งใหญ่ (การไตร่ตรอง) มาพร้อมกับความรับผิดชอบที่ยิ่งใหญ่และคุณควรใช้มันก็ต่อเมื่อคุณเข้าใจและพิจารณาถึงผลที่ตามมาแล้ว
c1moore

คำตอบ:


241

สองทาง:

วิธีที่ 1 - สำหรับคลาสที่มีตัวสร้างที่ไม่มีอาร์กิวเมนต์เท่านั้น

หากคลาสของคุณมีตัวสร้างที่ไม่มีอาร์กิวเมนต์คุณจะได้รับClassวัตถุโดยใช้Class.forName()และใช้newInstance()วิธีการสร้างอินสแตนซ์ (แต่โปรดระวังว่าวิธีนี้มักถูกมองว่าชั่วร้ายเพราะสามารถเอาชนะข้อยกเว้นที่ตรวจสอบของ Java ได้)

ตัวอย่างเช่น:

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

วิธีที่ 2

วิธีอื่นที่ปลอดภัยกว่าซึ่งใช้ได้ผลเช่นกันหากคลาสไม่มีตัวสร้างที่ไม่มีอาร์กิวเมนต์คือการสอบถามคลาสของคุณเพื่อรับConstructorอ็อบเจ็กต์และเรียกnewInstance()เมธอดบนอ็อบเจ็กต์นี้:

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

ทั้งสองวิธีนี้เรียกว่าการสะท้อน โดยทั่วไปคุณจะต้องตรวจสอบข้อยกเว้นต่างๆที่อาจเกิดขึ้นรวมถึงสิ่งต่างๆเช่น:

  • JVM ไม่พบหรือไม่สามารถโหลดชั้นเรียนของคุณได้
  • คลาสที่คุณพยายามสร้างอินสแตนซ์ไม่มีตัวสร้างที่ถูกต้อง
  • ตัวสร้างเองก็มีข้อยกเว้น
  • ตัวสร้างที่คุณพยายามเรียกใช้ไม่ได้เป็นแบบสาธารณะ
  • มีการติดตั้งตัวจัดการความปลอดภัยและป้องกันไม่ให้เกิดการสะท้อนกลับ

สวัสดีเมื่อเราสร้างวัตถุขึ้นมาnewInstance()แล้วเราจะโยนมันกลับไปที่วัตถุของเราเองได้ไหม
GMsoF

@ Simon คุณสามารถอธิบาย / ให้ตัวชี้เกี่ยวกับตัวจัดการความปลอดภัยได้หรือไม่?
ราม

ฉันไม่เข้าใจเรื่องนี้ ฉันต้องการเข้าถึงคลาสในไฟล์ที่ไม่รู้จักในไดเร็กทอรีอื่นฉันมีเพียงชื่อของพา ธ / ไฟล์เป็นสตริง สตริง "dir / unkonwn.java" การเรียก Class.forName ("dir / Unknown") ทำให้ฉันมีข้อผิดพลาด
john ktejik

เราจะหล่อinstanceไปได้com.foo.MyClassอย่างไร? เนื่องจากcom.foo.MyClassเป็นเพียงสตริง
Sanket9394

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

15
เป็นมูลค่าการกล่าวขวัญว่าสิ่งนี้ใช้ไม่ได้หากคลาสไม่มีตัวสร้างแบบไม่มีพารามิเตอร์ (และมีตัวสร้างอื่น ๆ ) หรือหากไม่สามารถเข้าถึงตัวสร้างแบบไม่มีพารามิเตอร์ได้
Dawood ibn Kareem

3

ใช้Class.forName ("ชื่อสตริงของคลาส") newInstance ();

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

สิ่งนี้จะทำให้คลาสชื่อ A เริ่มต้น


ไม่ได้ผลสำหรับฉันแม้ว่าจะมีชื่อแพ็กเกจอยู่ข้างหน้าก็ตาม :(
trusktr

3

เพื่อให้ง่ายต่อการรับชื่อแบบเต็มของคลาสเพื่อสร้างอินสแตนซ์โดยใช้Class.forName(...)เราสามารถใช้Class.getName()เมธอด สิ่งที่ต้องการ:

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;
    }
}

จากนั้นคุณสามารถโยนวัตถุที่คุณกลับไปยังคลาสใดก็ได้ที่คุณผ่านไปmakeObject(...):

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

1
คุณไม่สามารถเพียงแค่clazz.newInstance()แทนgetNameแล้วfromName?
user276648

1

ใช้การสะท้อน java

การสร้างอ็อบเจ็กต์ใหม่ไม่มีวิธีใดเทียบเท่ากับการเรียกใช้เมธอดสำหรับคอนสตรัคเตอร์เนื่องจากการเรียกใช้คอนสตรัคเตอร์เทียบเท่ากับการสร้างอ็อบเจ็กต์ใหม่ (เพื่อให้แม่นยำที่สุดการสร้างอ็อบเจ็กต์ใหม่เกี่ยวข้องกับการจัดสรรหน่วยความจำและการสร้างอ็อบเจ็กต์) ดังนั้นสิ่งที่ใกล้เคียงที่สุดกับตัวอย่างก่อนหน้านี้คือการพูดว่า:

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);
         }
      }
   }

ซึ่งค้นหาตัวสร้างที่จัดการกับชนิดพารามิเตอร์ที่ระบุและเรียกใช้เพื่อสร้างอินสแตนซ์ใหม่ของอ็อบเจ็กต์ คุณค่าของแนวทางนี้คือเป็นแบบไดนามิกโดยมีการค้นหาตัวสร้างและการเรียกใช้ ณ เวลาดำเนินการแทนที่จะเป็นเวลาคอมไพล์




0

อะไรแบบนี้น่าจะใช้ได้ ...

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

0

การใช้newInstance()โดยตรงจะเลิกใช้งานใน Java 8 คุณจำเป็นต้องใช้Class.getDeclaredConstructor(...).newInstance(...)กับข้อยกเว้นที่เกี่ยวข้อง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.