简体   繁体   中英

Class.getConstructor fails to find compatible constructor

Having problems with a factory class, I pass in a human readable name that maps to a class that has a single constructor with a single argument, I get the following error:

java.lang.NoSuchMethodException: com.satgraf.evolution2.observers.VSIDSTemporalLocalityEvolutionObserver.<init>(com.satlib.evolution.ConcreteEvolutionGraph)
at java.lang.Class.getConstructor0(Class.java:2892)
at java.lang.Class.getConstructor(Class.java:1723)
at com.satlib.evolution.observers.EvolutionObserverFactory.getByName(EvolutionObserverFactory.java:84)
at com.satgraf.evolution2.UI.Evolution2GraphFrame.main(Evolution2GraphFrame.java:229) 

These are the classes in question, I have about a dozen of these things in different projects, they all work without problem - including one that is almost identical, can't see why this one is failing:

public EvolutionObserver getByName(String name, EvolutionGraph graph){
if(classes.get(name) == null){
  return null;
}
else{
  try {
    Constructor<? extends EvolutionObserver> con = classes.get(name).getConstructor(graph.getClass());
    EvolutionObserver i = con.newInstance(graph);
    observers.add(i);
    return i;
  } 
  catch (InvocationTargetException | InstantiationException | IllegalAccessException | NoSuchMethodException | IllegalArgumentException | SecurityException ex) {
    Logger.getLogger(EvolutionObserverFactory.class.getName()).log(Level.SEVERE, null, ex);
    return null;
  }
}
}

The class being instantiated is:

public class VSIDSTemporalLocalityEvolutionObserver extends JPanel implements EvolutionObserver{
    public VSIDSTemporalLocalityEvolutionObserver(EvolutionGraph graph){
    ...
    }
...
}

The argument graph is of type:

public class ConcreteEvolutionGraph extends ConcreteCommunityGraph implements EvolutionGraph{
    ...
}

getConstructor requires an exact match on the parameter types; it does not attempt to find a 'compatible' constructor. The getConstructor Javadoc simply says "The constructor to reflect is the public constructor of the class represented by this Class object whose formal parameter types match those specified by parameterTypes ." (In current OpenJDK, getConstructor delegates to getConstructor0 which loops through all the constructors and compares the given parameter array against constructor.getParameterTypes() .)

At runtime, your code looks for a constructor taking a parameter of type ConcreteEvolutionGraph ( graph.getClass() returns graph 's runtime type), and VSIDSTemporalLocalityEvolutionObserver doesn't have one.

If you're really looking for a constructor taking EvolutionGraph , pass EvolutionGraph.class to getConstructor instead. If instead you want any constructor that could be called with the graph's runtime type, you'll need to manually loop over the result of getConstructors() looking for a single-argument constructor for which graph.getClass().isAssignableTo(ctor.getParameterTypes()[0]) . Note there may be more than one, and when interfaces are involved, there may not be a most-specific one. You'll have to decide how to break ties.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM