การสร้างอินสแตนซ์โดยใช้ชื่อคลาสและตัวสร้างการเรียก


312

มีวิธีสร้างอินสแตนซ์ของคลาสเฉพาะที่กำหนดชื่อคลาส (ไดนามิก) และส่งพารามิเตอร์ไปยังตัวสร้างหรือไม่

สิ่งที่ต้องการ:

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

ที่ไหนเป็นอาร์กิวเมนต์คอนสตรัคของ"MyAttributeValue"MyClass

คำตอบ:


497

ใช่บางสิ่งเช่น:

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

แน่นอนว่าจะใช้ได้กับพารามิเตอร์สตริงเดียวเท่านั้น แต่คุณสามารถแก้ไขได้อย่างง่ายดาย

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

package foo;

public class Outer
{
    public static class Nested {}
}

ที่จะได้รับวัตถุสำหรับการที่คุณจะต้องClassClass.forName("foo.Outer$Nested")


5
newInstance()เป็นวิธีการ varargs (เช่นเดียวกับGetConstructor()) ไม่จำเป็นต้องมีObjectการสร้าง -array อย่างชัดเจน
Joachim Sauer

18
@ โจอาคิม: ฉันรู้ว่ามันเป็น varargs แต่ถ้าหากคุณมีObject[]ข้อโต้แย้งฉันสามารถสร้างอาร์เรย์ได้อย่างชัดเจนในกรณีนี้
Jon Skeet

2
clazz.getConstructor (String.class); ทำไม String.class ที่นี่
Umair A.

2
@ Neutralizer: ใช่ แต่ฉันตอบคำถามที่ไม่จำเป็นต้องเป็นแบบไดนามิก
Jon Skeet

3
@ JonSkeet ฉันเข้าใจว่าคุณมาจากไหน แต่มันไม่ง่ายเลย - ฉันดูเอกสาร แต่ก็สับสน แต่ถ้าฉันทดสอบมันแล้วมันก็ใช้ได้ - ok มันใช้ได้แล้ว - แต่ถ้ามันไม่ทำงาน ฉันจะไม่แน่ใจถ้าปัญหาเกิดจากการขาดการกำหนดค่าหรือบางสิ่งบางอย่างในส่วนของฉัน - บ่อยครั้งเมื่อถามคำถามง่ายๆเช่นนั้น นั่นเป็นเหตุผลที่ง่าย "ใช่ที่จะทำงาน - ถ้าคุณทำอย่างนี้" หรือ "ไม่มีทาง" ช่วยได้จริงๆ แต่ตอนนี้ความเข้าใจของฉันคือว่าไม่มีทาง
ycomp

97

คุณสามารถใช้Class.forName()เพื่อรับClassวัตถุของคลาสที่ต้องการ

จากนั้นใช้getConstructor()เพื่อค้นหาสิ่งที่ต้องการConstructorวัตถุ

สุดท้ายให้โทรหาnewInstance()วัตถุนั้นเพื่อรับอินสแตนซ์ใหม่ของคุณ

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

81

คุณสามารถใช้การสะท้อน

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

3
หากใช้คอนสตรัคเตอร์ปริยายให้ลบค่าพารามิเตอร์ String.class เช่น return class.forName (className) .getConstructor (). newInstance (arg);
Vijay Kumar

21
@VijayKumar ฉันคิดว่าคุณหมายถึงClass.forName(className).getConstructor().newInstance();;)
Peter Lawrey

14

ถ้า class มี Constructor ว่างเปล่าเพียงอันเดียว (เช่น Activity หรือ Fragment เป็นต้น, คลาส Android):

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

2
นี่คือสิ่งที่ช่วยฉัน Constructor<?> ctor = clazz.getConstructor(String.class)ดูเหมือนจะไม่ได้ผลสำหรับฉัน
Leo C Han

8

เมื่อใช้ (เช่น) getConstructor(String.lang)ตัวสร้างจะต้องประกาศสู่สาธารณะ มิฉะนั้นNoSuchMethodExceptionจะถูกโยน

ถ้าคุณต้องการที่จะเข้าถึงตัวสร้างที่ไม่ใช่แบบสาธารณะคุณมีที่จะใช้แทน getDeclaredConstructor(String.lang)(IE)



4

วิธีที่ง่ายมากในการสร้างวัตถุใน Java โดยใช้การClass<?>ส่งผ่านอาร์กิวเมนต์ตัวสร้าง:

กรณีที่ 1: - นี่คือรหัสขนาดเล็กในMainชั้นนี้:

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

}

และนี่คือBaseโครงสร้างคลาส:

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

}

กรณีที่ 2: -คุณสามารถโค้ดในทำนองเดียวกันสำหรับคอนสตรัคเตอร์ที่มีอาร์กิวเมนต์หลายตัวและคัดลอกคอนสตรัคเตอร์ ตัวอย่างเช่นการส่งอาร์กิวเมนต์ 3 ตัวเป็นพารามิเตอร์ให้กับตัวBaseสร้างจะต้องใช้ตัวสร้างเพื่อสร้างในคลาสและการเปลี่ยนรหัสในด้านบนเป็น:

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

และที่นี่ชั้นฐานควรมีลักษณะอย่างไร:

public class Base {

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

หมายเหตุ: - อย่าลืมจัดการข้อยกเว้นต่าง ๆ ซึ่งจำเป็นต้องจัดการในรหัส


อีกวิธีคือโดย clone () วัตถุ java ที่มีอยู่ สิ่งนี้จะสร้างสำเนาของวัตถุ Java ที่มีอยู่ สำหรับกรณีนี้คุณต้องจัดการกับสำเนาลึกหรือแนวคิดคัดลอกตื้น
ราหุลเรน

2

หากใครกำลังมองหาวิธีในการสร้างตัวอย่างของชั้นเรียนแม้จะมีชั้นเรียนตามรูปแบบ Singleton นี่คือวิธีที่จะทำ

// 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();

ใช้งานได้กับคลาสที่ใช้รูปแบบซิงเกิลโดยใช้ Constructor ส่วนตัวเท่านั้น


1

นอกจากนี้คุณยังสามารถเรียกใช้วิธีการภายในวัตถุที่สร้างขึ้น

คุณสามารถสร้างออบเจกต์ได้ทันทีโดยเรียกใช้ constractor แรกจากนั้นเรียกใช้เมธอดแรกในวัตถุที่สร้างขึ้น

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

คุณจะรู้ได้อย่างไรว่าคอนสตรัคเตอร์ตัวแรกนั้นใช้Stringเป็นพารามิเตอร์ จะยุ่งเล็กน้อยเมื่อคุณเปลี่ยนคำสั่งคอนสตรัคเตอร์
Farid

@Farid จากเอกสารประกอบการเรียน
Hatem Badawi

ยังgetConstructor(ClassName.class)ดีกว่าฉันเดา แม้ว่าคำสั่งของผู้สร้างเปลี่ยนแปลงในชั้นเรียนไม่จำเป็นต้องค้นหาตำแหน่งด้วยตนเอง
Farid

@Farid - c.getDeclaredMethods () [0] .invoke (object, Object ... MethodArgs); ระบุตัวสร้างพิเศษในบางกรณีคุณอาจต้องการสิ่งนี้ แต่คุณพูดถูก
Hatem Badawi

1

อีกคำตอบที่เป็นประโยชน์ ฉันจะใช้ getConstructor (params) .newInstance (args) ได้อย่างไร

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

ในกรณีของฉันตัวสร้างคลาสของฉันใช้ Webdriver เป็นพารามิเตอร์ดังนั้นใช้โค้ดด้านล่าง:

return Class.forName("com.page.BillablePage")
    .getConstructor(WebDriver.class)
    .newInstance(this.driver);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.