2015-11-18 34 views
5

Böyle bir yöntemin nasıl yazılacağı konusunda herhangi bir ipucunuz var mı?Yansıma parametresi yerine Object [] nesnesini geçirerek bir sınıfın yeni örneğini oluşturma

public abstract class AbstractClass{} 

public class TrialClass extends AbstractClass{ 
    public TrialClass(final String a, final String b){} 
    public TrialClass(final String a, final String b, final String c){} 
} 

public class getNewInstance(final Class<? extends AbstractClass> clazz, Object... constructorParameters){ 
    //??? 
} 

TrialClass trialClass = getNewInstance(TrialClass.class, "A", "B"); 
+0

Parametreleri argümanlarla eşleşen yapıcı için yapıcı dizisini aramak zorundasınız. –

+0

'AbstractClass' nerede ortaya çıkıyor? Neden ihtiyaç duyuluyor? –

+0

Ve yöntem imzanız 'public T getNewInstance (final Sınıfı clazz, Object ... cs);' – Codebender

cevap

2

Class yöntem kurucu bağımsız tekabül eden bir parametre olarak Class bir dizi alan bir getConstructor yöntem içerir. Bu diziyi parametre dizinizden oluşturmalısınız. Böyle

şey:

public <T> T getNewInstance(final Class<T> clazz, Object... constructorParameters) throws InstantiationException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException{ 
    Class[] parameterTypes = new Class[constructorParameters.length]; 
    for(int i = 0; i < constructorParameters.length; i++) { 
     parameterTypes[i] = constructorParameters[i].getClass(); 
    } 

    Constructor<T> constructor = clazz.getConstructor(parameterTypes); 
    return constructor.newInstance(constructorParameters); 
} 

Düzenleme: Codebender söylediği gibi bir alt tipi değişken olarak geçirildiğinde, bu işe yaramaz.

+1

Bu, bir alt tür bağımsız değişken olarak iletildiğinde işe yaramıyor ... – Codebender

+0

tha, kurucunun doğru olduğunu buluyor, ancak newInstance oluşturmak için argümanların geçmesi bazı sorunlara yol açıyor. Bu yöntemi şöyle çağırırsak: getNewInstance (TrialClass.class, "A", "B"); constructorParametreler, "A" ve "B" içeren bir nesne dizisi olacaktır. Yani String, String parametreleri yerine Object dizisini geçirmeye çalışıyoruz. Bu kod muhtemelen IllegalArgumentException'ı atar. Bu örnek için – PRowLeR

+0

constructor.newInstance (constructorParameters [0], constructorParameters [1]) çalışır. – PRowLeR

3

Muhtemelen daha esnek bir yaklaşım bu gibi uyumlu bir bütün kurucular kontrol edip bulmaktır:

public static <T> T getNewInstance(final Class<T> clazz, Object... constructorParameters) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { 
    Constructor<?> candidate = null; 
    for(Constructor<?> constructor : clazz.getConstructors()) { 
     if(Modifier.isPublic(constructor.getModifiers()) && isConstructorCompatible(constructor, constructorParameters)) { 
      if(candidate == null) 
       candidate = constructor; 
      else 
       throw new IllegalArgumentException("Several constructors found which are compatible with given arguments"); 
     } 
    } 
    if(candidate == null) 
     throw new IllegalArgumentException("No constructor found which is compatible with given arguments"); 
    return (T) candidate.newInstance(constructorParameters); 
} 

private static boolean isConstructorCompatible(Constructor<?> constructor, Object[] constructorParameters) { 
    Class<?>[] parameterTypes = constructor.getParameterTypes(); 
    if(parameterTypes.length != constructorParameters.length) 
     return false; 
    for(int i=0; i<parameterTypes.length; i++) 
     if(!isParameterCompatible(parameterTypes[i], constructorParameters[i])) 
      return false; 
    return true; 
} 

private static boolean isParameterCompatible(Class<?> type, Object parameter) { 
    if(parameter == null) 
     return !type.isPrimitive(); 
    if(type.isInstance(parameter)) 
     return true; 
    if(type.isPrimitive()) { 
     if (type == int.class && parameter instanceof Integer 
       || type == char.class && parameter instanceof Character 
       || type == byte.class && parameter instanceof Byte 
       || type == short.class && parameter instanceof Short 
       || type == long.class && parameter instanceof Long 
       || type == float.class && parameter instanceof Float 
       || type == double.class && parameter instanceof Double 
       || type == boolean.class && parameter instanceof Boolean) 
      return true; 
    } 
    return false; 
} 

varargs-yapıcıları gibi olsa açık konular hala vardır. Ayrıca belirsizlik durumları javac tarafından yapıldığı gibi çözülmeyecektir (örneğin, MyObj(Object) ve MyObj(String) yapıcınız varsa, ikincisinin her ikisini de kullanamazsınız).