使用Java反射,如何获取指定构造函数参数的派生类的类的构造函数?
使用Java反射,可以通过使用Java反射,如何获取指定构造函数参数的派生类的类的构造函数?,java,reflection,clojure,Java,Reflection,Clojure,使用Java反射,可以通过getConstructor(klass,args)获得构造函数 但是,当我们作为args传递构造函数签名中指定的类的派生类时,它将失败。如何克服这个问题 比如说, HashSet.class.getConstructor(new Class[]{ HashSet.class }); 失败了。当 HashSet.class.getConstructor(new Class[]{ Collection.class }); 成功 我正在寻找可以在clojure中轻松使用
getConstructor(klass,args)
获得构造函数
但是,当我们作为args
传递构造函数签名中指定的类的派生类时,它将失败。如何克服这个问题
比如说,
HashSet.class.getConstructor(new Class[]{ HashSet.class });
失败了。当
HashSet.class.getConstructor(new Class[]{ Collection.class });
成功
我正在寻找可以在clojure
中轻松使用的东西。因此,我更喜欢开箱即用,而不必添加用户定义的函数
有没有办法,如何解决这个问题 没有
HashSet(HashSet)
constructor,所以当您请求它时,自然不会得到它。您必须通过与赋值兼容的类(至少在超级中循环,可能还有实现的接口和它们的超级)找到一个。这里不要混淆多态行为。因为,您是将集合作为具体值而不是参数类型传入(新类[]{Collection})。这是一种相当简单的方法。getConstructorForArgs
-方法遍历给定类中的所有构造函数,并检查构造函数的参数是否与给定的参数匹配(请注意,给定参数的顺序必须与构造函数中的顺序相同)。接口和子类的实现也起作用,因为“兼容性”是通过调用构造函数参数的isAssignableFrom
来检查的(给定的参数类型可分配给构造函数中的参数类型)
公共类ReflectionTest
{
公共构造函数getConstructorForArgs(类klass,类[]args)
{
//获取给定类中的所有构造函数
构造函数[]constructors=klass.getConstructors();
for(构造函数:构造函数)
{
//遍历所有构造函数,将参数数量和参数类型与给定类型(args)匹配
类[]类型=构造函数。getParameterTypes();
if(types.length==args.length)
{
布尔参数匹配=真;
对于(int i=0;i
编辑:请注意,此解决方案并非适用于所有情况:如果有两个构造函数具有可从给定参数类型分配的参数,则将选择第一个构造函数,即使第二个构造函数更适合。例如,如果
SomeClass
将有一个以HashSet
(一个Collection
-实现)为参数的构造函数,以及一个以Collection
为参数的构造函数,则该方法在搜索接受HashSet
为参数的构造函数时可以返回其中一个,这取决于迭代类时哪个先到。如果它也需要用于此类情况,您需要首先收集所有可能的候选人,这些候选人与isAssignableFrom
匹配,然后对候选人进行更深入的分析,以选择最适合的候选人。我想,您可以获取父类和所有已实现接口的列表-->以便首先检查Hashset的构造函数。如果未找到任何内容,则可以对所有父类和接口递归执行此操作,直到找到匹配的父类和接口。基于和的答案:
下面返回给定类的一系列构造函数,这些构造函数(1)可使用指定的参数类型调用,(2)在某种意义上是最优的,即它们声明的参数类型从指定的参数类型向继承阶梯上移除的步数最少。(因此是一张精确的垫子
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}) );
}
}
user> (find-best-constructors java.util.HashSet [:int :float])
(#<Constructor public java.util.HashSet(int,float)>)
user> (find-best-constructors java.util.HashSet [java.util.HashSet])
(#<Constructor public java.util.HashSet(java.util.Collection)>)
user> (find-best-constructors java.util.HashSet [Integer])
(#<Constructor public java.util.HashSet(int)>)
(defn find-best-constructors [klass args]
(let [keym {:boolean Boolean/TYPE
:byte Byte/TYPE
:double Double/TYPE
:float Float/TYPE
:int Integer/TYPE
:long Long/TYPE
:short Short/TYPE}
args (->> args
(map #(if (class? %) % (keyword %)))
(map #(keym % %)))
prims (map keym [:boolean :byte :double :float :int :long :short])
boxed [Boolean Byte Double Float Integer Long Short]
convm (zipmap (concat prims boxed) (concat boxed prims))
ctors (->> (.getConstructors klass)
(filter #(== (count args) (count (.getParameterTypes %))))
(filter #(every? (fn [[pt a]]
(or (.isAssignableFrom pt a)
(if-let [pt* (convm pt)]
(.isAssignableFrom pt* a))))
(zipmap (.getParameterTypes %) args))))]
(when (seq ctors)
(let [count-steps (fn count-steps [pt a]
(loop [ks #{a} cnt 0]
(if (or (ks pt) (ks (convm pt)))
cnt
(recur (set (mapcat parents ks)) (inc cnt)))))
steps (map (fn [ctor]
(map count-steps (.getParameterTypes ctor) args))
ctors)
m (zipmap steps ctors)
min-steps (->> steps
(apply min-key (partial apply max))
(apply max))]
(->> m
(filter (comp #{min-steps} (partial apply max) key))
vals)))))