Aquí hay una forma bastante sencilla de hacerlo. El getConstructorForArgs
-metodo recorre todos los constructores en una clase determinada, y comprueba si los parámetros del constructor coinciden con los parámetros dados (tenga en cuenta que los parámetros dados deben estar en el mismo orden que en el constructor). Las implementaciones de interfaces y subclases también funcionan, porque la "compatibilidad" se comprueba llamando al isAssignableFrom
para el argumento del constructor (es el tipo de parámetro dado asignable al tipo de parámetro en el constructor).
public class ReflectionTest
{
public Constructor<?> getConstructorForArgs(Class<?> klass, Class[] args)
{
//Get all the constructors from given class
Constructor<?>[] constructors = klass.getConstructors();
for(Constructor<?> constructor : constructors)
{
//Walk through all the constructors, matching parameter amount and parameter types with given types (args)
Class<?>[] types = constructor.getParameterTypes();
if(types.length == args.length)
{
boolean argumentsMatch = true;
for(int i = 0; i < args.length; i++)
{
//Note that the types in args must be in same order as in the constructor if the checking is done this way
if(!types[i].isAssignableFrom(args[i]))
{
argumentsMatch = false;
break;
}
}
if(argumentsMatch)
{
//We found a matching constructor, return it
return constructor;
}
}
}
//No matching constructor
return null;
}
@Test
public void testGetConstructorForArgs()
{
//There's no constructor in HashSet that takes a String as a parameter
Assert.assertNull(getConstructorForArgs(HashSet.class, new Class[]{String.class}));
//There is a parameterless constructor in HashSet
Assert.assertNotNull(getConstructorForArgs(HashSet.class, new Class[]{}));
//There is a constructor in HashSet that takes int as parameter
Assert.assertNotNull(getConstructorForArgs(HashSet.class, new Class[]{int.class}));
//There is a constructor in HashSet that takes a Collection as it's parameter, test with Collection-interface
Assert.assertNotNull(getConstructorForArgs(HashSet.class, new Class[]{Collection.class}));
//There is a constructor in HashSet that takes a Collection as it's parameter, and HashSet itself is a Collection-implementation
Assert.assertNotNull(getConstructorForArgs(HashSet.class, new Class[]{HashSet.class}));
//There's no constructor in HashSet that takes an Object as a parameter
Assert.assertNull(getConstructorForArgs(HashSet.class, new Class[]{Object.class}));
//There is a constructor in HashSet that takes an int as first parameter and float as second
Assert.assertNotNull(getConstructorForArgs(HashSet.class, new Class[]{int.class, float.class}));
//There's no constructor in HashSet that takes an float as first parameter and int as second
Assert.assertNull(getConstructorForArgs(HashSet.class, new Class[]{float.class, int.class}));
}
}
Editar: Tenga en cuenta que esta solución no es ideal para todos los casos: si hay dos constructores, que tienen un parámetro que se puede asignar a un tipo de parámetro dado, será elegido el primero, incluso si el segundo fue un mejor ajuste. Por ejemplo, si SomeClass
tuviera un constructor que tomara HashSet
(A Collection
-implementation) como parámetro, y un constructor tomando Collection
como parámetro, el método podría devolver cualquiera de los dos cuando busque un constructor que acepte un parámetro HashSet
, dependiendo de cuál vino primero al iterar a través de las clases. Si necesita funcionar también para esos casos, primero debe reunir todos los candidatos posibles, que coincidan con isAssignableFrom
, y luego hacer un análisis más profundo para que los candidatos elijan el más adecuado.
¡Guau! Un poco de código.¿Podría proporcionar un archivo clj ejecutable que demuestre cómo llamar a 'find-best-constructors' con' HashSet' por ejemplo. – viebel
Bueno, hay tres ejemplos en la respuesta. Puede copiar las expresiones a la derecha de 'user>' en su propio archivo REPL/y verificar que los valores devueltos sean los que se anuncian. –
De alguna manera, aparece un error al importar HashSet. Puede acceder a mi archivo en: [find-constructors.clj] (https://github.com/viebel/Learning/blob/master/clojure/find-constructors.clj). Su sintaxis ' – viebel