2016-06-17 17 views
-1

Dies ist aus dem Minecraft-Server-Quellcode, auch Minecraft Bukkit API genannt, jetzt wissen Sie so viel wie ich.Wie wird diese Schnittstelle instanziiert?

Es gibt eine Schnittstelle Server genannt:

public interface Server extends PluginMessegeRecipient { 
    public String getVersion(); 
} 

PluginMessageRecipient ist eine Schnittstelle auch.

Es gibt eine Klasse namens Bukkit die Server instanziiert:

public final class Bukkit { 
    private static Server server; 

} 

Innen Methoden in der Bucket Klasse sie Methoden aus dem Server-Objekt aufrufen. Zum Beispiel:

server.getVersion(); 

Die Sache ist, gibt es keinen Code für getVersion in der Server-Schnittstelle, nur eine Methode Signatur. Es gibt auch keinen Code in der PluginMessageRecipient-Schnittstelle, noch wird etwas erweitert.

Ich habe alle Fragen und Antworten zu SO gelesen, die sagen, ich brauche eine anonyme Klasse oder eine innere Klasse und das scheint nicht zu diesen Lösungen zu passen.

+1

Ich vermute, dass 'server' irgendwann zu einer Durchführungsklasse der' Server' Schnittstelle instanziiert wird. ZB: 'Bucket.server = new VersionFiveServer()' und 'VersionFiveServer implementiert Server'. – CollinD

+1

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

+0

In Verbindung stehend: http://stackoverflow.com/questions/383947/what-does-it-mean-to-program-to-an-interface –

Antwort

1

Es gibt eine Klasse namens Bucket die Server instanziiert:

Eigentlich ist Bucket nicht Server instanziiert. Die Klasse Bucket enthält eine Referenz auf eine Server. Sie haben nicht gezeigt, wie das eingestellt wurde, so dass wir die tatsächliche Klasse nicht kennen.

ist jedoch sichergestellt, dass das, was zu dieser Referenz (Bucket.server) zugeordnet ist, vorausgesetzt, es ist nicht null ist, ist eine Aufgabe, einige konkrete Klasse, die Server implementiert. Diese Klasse wird eine Implementierung von getVersion() bereitstellen, und das wird so genannt.

+0

"Der Klasseneimer enthält einen Verweis auf einen Server. Sie haben nicht gezeigt, wie das eingestellt wurde, so dass wir die tatsächliche Klasse nicht kennen." - Es gibt keinen. Ich kann es nicht zeigen. Das ist meine Frage. – nicomp

+0

Es wurde irgendwo eingestellt, also "Es gibt keins" ist falsch im Gesicht. Sie sagen, es ist eine API, also gab es irgendwo irgendwo einen Aufruf oder eine Konfigurationsdatei (XML, JSON, Eigenschaften, ...) oder irgendwo eine Befehlszeilenoption, kombiniert mit irgendeiner Art von Initialisierungscode, der den Implementierungsklasse. Du hast es einfach noch nicht gefunden. Haben Sie die Dokumentation für die API ausprobiert? –

0

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:

  1. Die Klasse hat Standardzugriffs
  2. Die Klasse selbst nur eine Standard-Zugriffs statische Referenz hat
  3. Die Klasse hat Nur ein statisches String-Standardfeld für den Zugriff. Diese Regel gibt nur eine Klasse
  4. 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(); 
} 
+0

Tatsächlich arbeitet Bukkit von einem bereits entschleierten Jar (und hat eine konkrete Implementierung, 'CraftServer', die zwar benutzerdefiniert ist, obwohl andere Teile von CraftBukkit auf den Vanilla-Code verweisen). – Pokechu22