Wenn ich mich richtig erinnere, wird die bestimmte konkrete Klasse, die ausgewählt wird, zur Laufzeit durch Reflexion bestimmt. Da Minecraft keine Open-Source-Software ist, verfügen alle Entwickler über die verschleierten kompilierten Klassendateien, mit denen gearbeitet werden kann.
Der Code durchsucht jede Klassendatei im Minecraft Jar, sucht nach einer Klasse, die bestimmte Bedingungen erfüllt, und erzwingt dann mithilfe einer Bytecode-Bibliothek diese Klasse, um diese Schnittstelle zu implementieren.
Zum Beispiel, sagen wir mal, dass die folgende (verschleiert) Klasse der echteServer
Klasse im Code war Mine
class a {
String x_x317() {
return q_q98;
}
static a a_a1;
static String q_q98 = "1.9.4";
}
In diesem Fall wird die Methode x_x317
die Version String zurückgibt. Das Werkzeug, das sie auch Haken in dieser Klasse erlaubt könnte es auf den folgenden Bedingungen tun basiert:
- Die Klasse hat Standardzugriffs
- Die Klasse selbst nur eine Standard-Zugriffs statische Referenz hat
- Die Klasse hat Nur ein statisches String-Standardfeld für den Zugriff. Diese Regel gibt nur eine Klasse
- Die Klasse hat eine einzige Methode, die Standard-Zugriff hat, die
String
, und der zurückgegebene Wert gibt die FieldRef
in 3.
gefunden. Falls mehrere zurückgegeben werden (normalerweise in der Entwicklungsphase der neuen Bukkit-Version), werden sie spezifischer mit ihren Bedingungen behandelt, um sicherzustellen, dass sie nur die richtige Klasse zurückgeben. Sie tun dies für jedes Feld, jede Klasse und jede Methode, die sie identifizieren müssen.
Da sie nun wissen, welche Klasse die Klasse Server
ist, können sie Änderungen vornehmen. Zuerst müssten sie die Schnittstelle
class a implements org.bukkit.Server
Und dann implementieren die Methode
class a implements org.bukkit.Server {
String x_x317() {
return q_q98;
}
public String getVersionNumber() {
return x_x317();
}
static a a_a1;
static String q_q98 = "1.9.4";
}
Jetzt implementieren wir eine Klasse, die auf der Bukkit API entspricht.
Wenn sie diese Klasse instanziiert müssen, sie tun nur etwas entlang der Linien von
Server server = findAndTransformServerClassFromMinecraftJar();
// ...
Server findAndTransformServerClassFromMinecraftJar() {
// load classes from jar
// map them to the appropriate interfaces
// transform and hook the required classes and methods
Class<?> serverClass = doTheFirstThreeSteps();
return (Server) serverClass.newInstance();
}
Ich vermute, dass 'server' irgendwann zu einer Durchführungsklasse der' Server' Schnittstelle instanziiert wird. ZB: 'Bucket.server = new VersionFiveServer()' und 'VersionFiveServer implementiert Server'. – CollinD
Server ist eine Schnittstelle, daher wird es keinen Code haben. Es wird nur die Methodensignatur haben. Das ist, was eine Schnittstelle ist. Eine andere Klasse implementiert diese Schnittstelle und enthält Code. – ManoDestra
In Verbindung stehend: http://stackoverflow.com/questions/383947/what-does-it-mean-to-program-to-an-interface –