Zuallererst lese ich Erickson nützliche Antwort auf "Why can’t I define a static method in a Java interface?". Bei dieser Frage geht es nicht um das "Warum", sondern um das "Wie dann?". Gibt es eine Möglichkeit, sicherzustellen, dass Klassen, die ein Interface implementieren, statische Methoden implementieren?
Edit: mein ursprüngliches Beispiel wurde schlecht gestellt, aber ich lasse es unten.
Während ich jetzt bin überzeugt, dass in den meisten Fällen, was ich will viel des Guten zu tun ist, gibt es ein Szenario, wo sie gebraucht werden:
Ich werde wieder das ParametricFunction
Beispiel. Nehmen wir nun eine komplizierte Funktion, wie die Bessel functions, wo eine Nachschlagetabelle geeignet ist. Dies muss initialisiert werden, so dass die beiden Optionen die Parameter direkt an den Konstruktor übergeben oder init(double[] parameters)
bereitstellen. Letzteres hat den Nachteil, dass getValue(double x)
die Initialisierung jeden Anruf überprüfen muss (oder die ArrayIndexOutOfBoundsException
muss als Initialisierung Prüfung berücksichtigt werden), so dass für zeitkritische Anwendungen, die ich den Konstruktor-Methode bevorzugen würde:
interface ParametricFunction {
public double getValue(double x);
}
class BesselFunction implements ParametricFunction {
public BesselFunction(double[] parameters) { ... }
public double getValue(double x) { ... }
}
Welche berührt ein weiteres Problem, die Unmöglichkeit von Konstruktoren in Schnittstellen. Was wäre da eine gute Lösung? Ich könnte natürlich den init(double[] parameters)
Ansatz verwenden, aber ich erwähnte meinen Grund warum nicht.
(Edit: OK, hier eine abstrakte Klasse die Schnittstelle implementiert tun würde)
Nun lasst uns den ParametricFunction
annehmen können nur bestimmte Parameter, beispielsweise positive ganze Zahlen. Wie überprüft man die Gültigkeit der Parameter, die an den Konstruktor übergeben werden? Eine IllegalArgument
-Ausgabe zu werfen wäre eine Möglichkeit, aber eine scheint viel bequemer. Aber die Überprüfung der Parameter muss vor der Konstruktion erfolgen, also muss es eine statische Methode sein. Und hier würde ich wirklich gerne einen Weg finden, um sicherzustellen, dass jede Klasse, die die ParametricFunction
Schnittstelle implementiert, diese statische Methode definiert.
Ich weiß, dass dieses Beispiel eher künstlich ist, und der Grund dafür, nicht einfach eine init
Methode über die Schnittstelle zu verwenden, ist umstritten, ich würde immer noch gerne die Antwort wissen. Betrachten Sie es als akademische Frage, wenn Sie es nicht mögen.
(original Beispiel)
Also im Grunde möchte ich eine Schnittstelle sowohl übliche Verfahren und z.B. eine getSimilarObject
Methode. Für (eine aus) Beispiel
public interface ParametricFunction {
/** @return f(x) using the parameters */
static abstract public double getValue(double x, double[] parameters);
/** @return The function's name */
static abstract public String getName();
/** @return Whether the parameters are valid [added on edit] */
static abstract public boolean checkParameters(double[] parameters);
}
und dann
public class Parabola implements ParametricFunction {
/** @return f(x) = parameters[0] * x² + parameters[1] * x + parameters[2] */
static public double getValue(double x, double[] parameters) {
return (parameters[2] + x*(parameters[1] + x*parameters[0]));
}
static public String getName() { return "Parabola"; }
// edit:
static public boolean checkParameters(double[] parameters) {
return (parameters.length==3);
}
}
Da dies nicht im aktuellen Java-Standard erlaubt, was ist die nächste Sache, das?
Die Idee dahinter ist, mehrere ParametricFunction
s in ein Paket zu setzen und Reflection zu verwenden, um alle aufzulisten, so dass der Benutzer z. welches zu plotten. Natürlich könnte man eine Loader-Klasse bereitstellen, die ein Array der verfügbaren ParametricFunction
s enthält, aber jedes Mal, wenn ein neues implementiert wird, muss man sich auch daran erinnern, es dort hinzuzufügen.
edit: Ein Beispiel zu nennen ist
public double evaluate(String fnName, double x, double parameters) throws (a lot) {
Class<ParametricFunction> c = (Class<ParametricFunction>) ClassLoader.getSystemClassLoader().loadClass(fnName);
Method m = c.getMethod("getValue", x, parameters);
return ((double) m.invoke(null));
}
und ruft evaluate("Parabola", 1, new double[]{1,2,0});
.
Warum muss getValue statisch sein? Sie könnten genau das tun, was Sie wollen, wenn getValue nicht statisch ist. – nos
Dann müsste ich eine Instanz der Klasse erstellen. Korrigiere mich, wenn ich falsch liege, aber in Bezug auf seinen Zweck scheint das hier nicht nützlich zu sein. –
Was ist falsch ist dein Design. Es ist nicht OO. parameter [] sollte ein Instanzfeld der Parabola-Klasse sein, im Konstruktor gesetzt und überprüft und in der Klasse getValue() verwendet werden. –