Membuat instance menggunakan nama kelas dan memanggil konstruktor

312

Apakah ada cara untuk membuat turunan dari kelas tertentu yang diberi nama kelas (dinamis) dan meneruskan parameter ke konstruktornya.

Sesuatu seperti:

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

Di mana "MyAttributeValue"argumen untuk konstruktor MyClass.

TheLameProgrammer
sumber

Jawaban:

497

Ya, sesuatu seperti:

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

Itu hanya akan berfungsi untuk parameter string tunggal saja, tetapi Anda dapat memodifikasinya dengan mudah.

Perhatikan bahwa nama kelas harus yang sepenuhnya memenuhi syarat, yaitu termasuk namespace. Untuk kelas bersarang, Anda perlu menggunakan dolar (seperti itulah yang digunakan kompiler). Sebagai contoh:

package foo;

public class Outer
{
    public static class Nested {}
}

Untuk mendapatkan Classobjek untuk itu, Anda perlu Class.forName("foo.Outer$Nested").

Jon Skeet
sumber
5
newInstance()adalah metode varargs (sama seperti GetConstructor()), tidak perlu untuk Objectpenciptaan -array eksplisit .
Joachim Sauer
18
@ Joachim: Saya tahu ini varargs, tetapi karena bisa rumit ketika Anda memiliki Object[]argumen, saya lebih suka membuat array secara eksplisit dalam kasus ini.
Jon Skeet
2
clazz.getConstructor (String.class); mengapa String.class di sini?
Umair A.
2
@Neutralizer: Ya, tapi saya menjawab pertanyaan yang tidak perlu dinamis.
Jon Skeet
3
@ JonSkeet Saya mengerti dari mana Anda berasal, tetapi tidak sesederhana itu - saya memang melihat dokumen tetapi bingung, tetapi juga jika saya mengujinya dan bekerja - ok lalu berhasil - tetapi jika tidak berhasil maka Saya tidak yakin apakah masalahnya disebabkan oleh kurangnya konfigurasi atau sesuatu di pihak saya - seringkali ketika mengajukan pertanyaan sederhana seperti itu, orang-orang memberikan informasi yang berguna yang sangat membantu. Itu sebabnya "ya itu akan berhasil - jika Anda melakukannya dengan cara ini" atau "tidak, tidak ada cara", sangat membantu. Tapi pemahaman saya sekarang adalah bahwa tidak mungkin
ycomp
97

Anda dapat menggunakan Class.forName()untuk mendapatkan Classobjek dari kelas yang diinginkan.

Kemudian gunakan getConstructor()untuk menemukan Constructorobjek yang diinginkan .

Akhirnya, panggil newInstance()objek itu untuk mendapatkan contoh baru Anda.

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

Anda dapat menggunakan refleksi

return Class.forName(className).getConstructor(String.class).newInstance(arg);
Peter Lawrey
sumber
3
Jika menggunakan konstruktor default, hapus nilai parameter String.class misalnya return Class.forName (className) .getConstructor (). NewInstance (arg);
Vijay Kumar
21
@ VijayKumar Saya pikir maksud Anda Class.forName(className).getConstructor().newInstance();;)
Peter Lawrey
14

Jika kelas hanya memiliki satu konstruktor kosong (seperti Activity atau Fragment dll, kelas android):

Class<?> myClass = Class.forName("com.example.MyClass");    
Constructor<?> constructor = myClass.getConstructors()[0];
tier777
sumber
2
Inilah yang membantu saya. Constructor<?> ctor = clazz.getConstructor(String.class)sepertinya tidak bekerja untuk saya.
Leo C Han
8

saat menggunakan (yaitu) getConstructor(String.lang), konstruktor harus dinyatakan publik. Kalau tidak NoSuchMethodExceptiondilemparkan a.

jika Anda ingin mengakses konstruktor non-publik, Anda harus menggunakan (yaitu) getDeclaredConstructor(String.lang).

matthiasboesinger
sumber
4

Cara yang sangat sederhana untuk membuat objek menggunakan Java Class<?>dengan argumen konstruktor yang lewat:

Kasus 1: - Di sini, adalah kode kecil di Mainkelas ini :

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

}

Dan, inilah Basestruktur kelasnya:

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

}

Kasus 2: - Anda, dapat mengkode yang sama untuk konstruktor dengan beberapa argumen dan menyalin konstruktor. Misalnya, meneruskan 3 argumen sebagai parameter ke Basekonstruktor akan memerlukan konstruktor yang akan dibuat di kelas dan perubahan kode di atas sebagai:

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

Dan di sini kelas Basis entah bagaimana akan terlihat seperti:

public class Base {

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

Catatan: - Jangan lupa untuk menangani berbagai pengecualian yang perlu ditangani dalam kode.

Rahul Raina
sumber
Cara lain juga dengan mengkloning () objek java yang ada. Ini membuat salinan dari objek Java yang ada. Untuk kasus ini, Anda juga harus menangani konsep Salinan Jauh atau Salinan Dangkal.
Rahul Raina
2

Jika ada yang mencari cara untuk membuat instance kelas meskipun kelas mengikuti Pola Singleton, berikut adalah cara untuk melakukannya.

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

Ini hanya berfungsi untuk kelas yang menerapkan pola tunggal menggunakan konstruktor pribadi.

Omer
sumber
1

Anda juga dapat memanggil metode di dalam objek yang dibuat.

Anda bisa membuat objek instan dengan memanggil konstruktor pertama dan kemudian memanggil metode pertama dalam objek yang dibuat.

    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);
Hatem Badawi
sumber
Bagaimana Anda tahu bahwa konstruktor pertama mengambil Stringsebagai parameter? Menjadi sedikit berantakan ketika Anda mengubah urutan konstruktor
Farid
@Farid dari dokumentasi kelas
Hatem Badawi
Masih getConstructor(ClassName.class)lebih baik, kurasa. Bahkan jika urutan konstruktor berubah di kelas, tidak perlu menemukan posisi secara manual
Farid
@Farid - c.getDeclaredMethods () [0] .invoke (objek, Obyek ... MethodArgs); menentukan konstruktor khusus dalam beberapa kasus Anda mungkin memerlukan ini, tetapi Anda benar.
Hatem Badawi
1

Jawaban bermanfaat lainnya. Bagaimana cara menggunakan getConstructor (params) .newInstance (args)?

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

Dalam kasus saya, konstruktor kelas saya menggunakan Webdriver sebagai parameter, jadi gunakan kode di bawah ini:

return Class.forName("com.page.BillablePage")
    .getConstructor(WebDriver.class)
    .newInstance(this.driver);
pengguna3181500
sumber