getDeclaredConstructor没有找到带接口作为参数的构造函数

时间:2017-10-17 09:27:36

标签: java reflection

我有一个界面

public interface IDrawing

接下来我有一个实现此接口的类:

public class Line implements IDrawing

现在我有一个带有构造函数的类,它接受上面的参数:

public LineChanger(Line line)

没有问题。

当我使用反射调用上面的构造函数时,它会抛出NoSuchMethodException

//drawing variable is of class Line implementing IDrawing
.getDeclaredConstructor(IDrawing.class).newInstance(drawing);

当我将构造函数更改为:

时,异常消失了
public LineChanger(IDrawing line)

是否可以在不更改构造函数的情况下使反射工作?

我希望保持构造函数的严格性(即在这种情况下只接受一个特定的类Line),但保持反射适用于我的工厂。

3 个答案:

答案 0 :(得分:2)

public LineChanger(Line line)
  

当我使用反射调用上面的构造函数时,它会抛出NoSuchMethodException

只有你弄错了。

//drawing variable is of class Line implementing IDrawing
.getDeclaredConstructor(IDrawing.class).newInstance(drawing);

你弄错了。参数的类型为Line.class,而不是IDrawing.class

  

当我将构造函数更改为:

时,异常消失了
public LineChanger(IDrawing line)

当然可以。当您这样做时,您的Java代码和反射代码都是一致的。如果他们没有,它就无法工作,可以吗?

  

是否可以在不更改构造函数的情况下使反射工作?

是的,请致电.getDeclaredConstructor(Line.class).newInstance(drawing);,前提是drawingLine的实例。

你似乎在期待奇迹。

答案 1 :(得分:1)

当您调用getConstructor时,API会找到具有该签名的构造函数,因此如果没有构造函数采用IDrawing参数,则代码会抛出异常。

无论如何,API的行为都没有意义。您无法将类型为IDrawing的对象传递给Line类型的参数,因为您传递的对象可以是IDrawing的任何实现。

但是,反过来是可行的,您可以将Line类型的对象传递给采用IDrawing的构造函数。这是一个方法,它查找可以传递给定类型集的所有构造函数。

public static List<Constructor<?>> getCompatibleConstructors(Class<?> clazz, Class<?>... parameterTypes) {
    Constructor<?>[] ctrs = clazz.getConstructors();
    ArrayList<Constructor<?>> list = new ArrayList<>();
    outer: for (Constructor<?> ctr : ctrs) {
        if (ctr.getParameterCount() == parameterTypes.length) {
            for (int i = 0 ; i < parameterTypes.length ; i++) {
                if (!ctr.getParameterTypes()[i].isAssignableFrom(parameterTypes[i])) {
                    continue outer;
                }
            }
            list.add(ctr);
        }
    }
    return list;
}

它可以找到这个构造函数:

 public MyClass(IDrawing drawing) {}

如果您传递这些参数:

 getCompatibleConstructors(MyClass.class, Line.class);

答案 2 :(得分:1)

如果遍历所有构造函数并找到只有一个可从IDrawing分配的参数的构造函数,就有可能按照您想要的方式进行构建。

    Constructor ctor = Arrays.stream(LineChanger.class.getConstructors())
            .filter(c -> c.getParameterCount() == 1)
            .filter(c -> c.getParameterTypes()[0].isAssignableFrom(IDrawing.class))
            .findFirst()
            .orElse(LineChanger.class.getConstructors()[0]);