Sınıf adını ve çağrı yapıcısını kullanarak örnek oluşturma


312

Sınıf adı (dinamik) verilen belirli bir sınıfın bir örneğini oluşturmanın ve yapıcısına parametreleri iletmenin bir yolu var mı?

Gibi bir şey:

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

'Nin "MyAttributeValue"yapıcısına bir argüman nerede MyClass.

Yanıtlar:


497

Evet, şuna benzer:

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

Bu sadece tek bir dize parametresi için elbette işe yarayacaktır, ancak bunu kolayca değiştirebilirsiniz.

Sınıf adının tam olarak nitelenmesi gerektiğini, yani ad alanını içerdiğini unutmayın. Yuvalanmış sınıflar için bir dolar kullanmanız gerekir (derleyicinin kullandığı budur). Örneğin:

package foo;

public class Outer
{
    public static class Nested {}
}

Bunun için Classnesneyi elde etmek için ihtiyacınız olacak Class.forName("foo.Outer$Nested").


5
newInstance()bir varargs yöntemidir (tıpkı GetConstructor()), açık- Objectdizi oluşturmaya gerek yoktur .
Joachim Sauer

18
@Joachim: Bunun varargs olduğunu biliyorum, ancak bir Object[]argümanınız olduğunda zor olabileceğinden , bu durumda diziyi açıkça oluşturmayı tercih ederim.
Jon Skeet

2
clazz.getConstructor (String.class); Neden String.class burada?
Umair A.19

2
@Neutralizer: Evet, ancak dinamik olması gerekmediği bir soruyu yanıtlıyordum.
Jon Skeet

3
@JonSkeet Nereden geldiğinizi anlıyorum, ancak o kadar basit değil - belgelere baktım ama kafam karıştı, ama aynı zamanda test ettim ve çalıştıysa - tamam o zaman işe yaradı - ama işe yaramadıysa Sorunun bazı konfigürasyon eksikliğinden veya benim tarafımdaki bir şeyden kaynaklanıp kaynaklanmadığından emin olmazdım - genellikle bu kadar basit sorular sorurken, insanlar gerçekten yardımcı olan yararlı ipuçları atarlar. Bu yüzden basit bir "evet işe yarayacak - eğer bu şekilde yaparsanız" veya "hayır yolu yok", gerçekten yardımcı olur. Ama şimdi benim anlayışım hiçbir yolu yok
ycomp

97

İstediğiniz sınıfın Class.forName()bir Classnesnesini almak için kullanabilirsiniz .

Sonra getConstructor()istediğiniz Constructornesneyi bulmak için düğmelerini kullanın .

Son olarak, newInstance()yeni örneğinizi almak için bu nesneyi çağırın .

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

81

Yansımaları kullanabilirsiniz

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

3
Varsayılan yapıcı kullanılıyorsa, String.class parametre değerini kaldırın, örneğin return Class.forName (className) .getConstructor (). NewInstance (arg);
Vijay Kumar

21
@VijayKumar demek istediğini düşünüyorum Class.forName(className).getConstructor().newInstance();;)
Peter Lawrey

14

Sınıfta yalnızca bir boş oluşturucu varsa (Etkinlik veya Parça vb., Android sınıfları gibi):

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

2
Bu bana yardımcı oldu. Constructor<?> ctor = clazz.getConstructor(String.class)benim için işe yaramadı.
Leo C Han

8

(yani) getConstructor(String.lang)kullanılırken kurucu kamuya açıklanmalıdır. Aksi takdirde a NoSuchMethodExceptionatılır.

halka açık olmayan bir kurucuya erişmek istiyorsanız bunun yerine kullanmalısınız (yani) getDeclaredConstructor(String.lang).



4

Class<?>Geçiş yapıcı argümanları ile Java kullanarak bir nesne oluşturmak için çok basit bir yol :

Durum 1: - İşte, bu Mainsınıftaki küçük bir kod :

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

}

Ve burada Basesınıf yapısı:

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

}

Durum 2: - Siz, benzer bir şekilde birden fazla argüman ve kopya oluşturucu ile yapıcı için kod yazabilirsiniz. Örneğin, kurucuya parametre olarak 3 argüman iletmek Baseiçin kurucunun sınıfta oluşturulması ve yukarıdaki kod değişikliğinin aşağıdaki gibi olması gerekir:

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

Ve burada Base sınıfı bir şekilde şöyle görünmelidir:

public class Base {

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

Not: - Kodda ele alınması gereken çeşitli istisnaları ele almayı unutmayın.


Başka bir yol da mevcut java nesnesinin clone () yöntemidir. Bu, varolan bir Java nesnesinin bir kopyasını oluşturur. Bu durumda, Derin kopya veya Sığ kopya kavramını da ele almanız gerekir.
Rahul Raina

2

Eğer kimse Singleton Paternini takip eden sınıfa rağmen bir sınıf örneği oluşturmanın bir yolunu arıyorsa, bunu yapmanın bir yolu var.

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

Bu, yalnızca özel bir kurucu kullanarak singleton kalıbı uygulayan sınıflar için geçerlidir.


1

Oluşturulan nesnenin içindeki yöntemleri de çağırabilirsiniz.

İlk iletkeni çağırarak nesne anında oluşturabilir ve sonra oluşturulan nesnede ilk yöntemi çağırabilirsiniz.

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

İlk kurucunun Stringparametre olarak aldığını nasıl anlayacaksınız ? Yapıcı sırasını değiştirdiğinizde biraz dağınık hale gelir
Farid

@Sınıf belgelerinden uzak
Hatem Badawi

Hala getConstructor(ClassName.class)daha iyi, sanırım. Yapıcıların sırası sınıfta değişse bile, pozisyonu manuel olarak bulmaya gerek yok
Farid

@Farid - c.getDeclaredMethods () [0] .invoke (object, Object ... MethodArgs); bazı durumlarda özel kurucuyu belirtir, buna ihtiyacınız olabilir; ancak haklısınız.
Hatem Badawi

1

Başka bir yardımcı cevap. GetConstructor (params) .newInstance (args) nasıl kullanılır?

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

Benim durumumda, sınıfımın kurucusu Webdriver'ı parametre olarak alır, bu nedenle aşağıdaki kod kullanılır:

return Class.forName("com.page.BillablePage")
    .getConstructor(WebDriver.class)
    .newInstance(this.driver);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.