Die Antwort lautet einfach: "Wirf dich nicht in deinem Agent-Code an GameState!".
Alternativ kannst du das GameState-Material als privat deklarieren. Oder wenn Sie von einigen wenigen anderen Klassen darauf zugreifen müssen, deklarieren Sie es als paketgeschützt.
Ich habe den Code eines einfachen Spiels, in dem ein AgentInterface implementiert werden muss, um einen Agenten-Controller für einen der Charaktere im Spiel zu erstellen. GameState ist eine Klasse, die das GameStateInterface implementiert, und ein Objekt, das diese Schnittstelle implementiert, kann an den Agenten übergeben werden, sodass der Agent die Daten aus dem Spielzustand lesen und analysieren kann und der Agent die entsprechende Aktion (als int zurückgegeben) zurückgeben muss der Charakter sollte nehmen.
Dies ist das AgentInterface, das Agents implementieren müssen:
%Vor%Ausführen des Spiels mit einem Agenten namens MyAgent:
%Vor%Aber es gibt einige Informationen in GameState, auf die der Agent NICHT zugreifen darf, da dies den Controller betrügen würde. Eine Cast-Konvertierung von GameStateInterface in GameState würde es dem Agenten jedoch ermöglichen, auf Informationen zuzugreifen, die nicht im GameStateInterface definiert sind:
%Vor%Meine Frage wäre, ist es möglich, eine Cast-Conversion zu blockieren? Ich weiß, dass Polymorphie eines der Hauptmerkmale von Java und objektorientierten Programmiersprachen ist, aber in solchen Fällen möchte ich Umwandlungen vermeiden.
Ich weiß, dass dies auf viele andere Arten gelöst werden kann, aber ich war neugierig zu wissen, ob es möglich ist, dies zu tun.
Vielen Dank im Voraus.
Es ist nicht möglich, einen Cast zu blockieren. Sie können Ihren Spielstatus jedoch so definieren, dass er nur von einem bestimmten Ort aus erstellt werden kann. Eine Sache, die Ihnen in den Sinn kommt, wäre eine private innere Klasse, die die Schnittstelle implementiert, oder eine Factory, die eine private innere Klasseninstanz zurückgibt
Soweit ich weiß, ist es nicht möglich, eine Typumwandlung abzufangen und zu leugnen (z. B. durch eine ClassCastException).
Aber anstatt zu versuchen, das Typecase zu leugnen, kannst du einfach das Proxymuster verwenden, um den Zugriff auf den eigentlichen GameState zu kontrollieren Objekt. Implementiere einfach eine Proxy-Klasse, die nur das GameStateInterface implementiert und es alle Methodenaufrufe an das GameState-Objekt weiterleiten lässt. Anstatt den tatsächlichen GameState-Objektverweis an die Aktionsmethode zu übergeben, übergeben Sie ihn nun von einer Instanz Ihrer Proxyklasse umschlossen.
Wenn Sie Bedenken haben, dass der Spielstatus von einem Agenten geändert wird, erstellen Sie eine Bean-Kopie des Status und übergeben Sie diese an den Agenten und nicht an das echte GameState-Objekt.
Es ist nicht möglich, einen Cast zu verbieten (es ist wahrscheinlich eine nicht sperrbare JVM-Sprachspezifikation), oder ich habe noch nie davon gehört.
Im Allgemeinen können Sie nicht verhindern, dass ein Objekt in Java umgewandelt wird. Der Code, der einen Verweis auf Ihre %code% erhält, kann eine nicht private, nicht geschützte Methode für dieses Objekt aufrufen. Selbst wenn Sie Casting verhindern könnten, könnte es immer noch Reflexion verwenden.
Wenn der %code% -Code unter Ihrer Kontrolle steht, halten Sie die Dinge einfach und werfen Sie sie nicht um. Wenn andere %code% -Klassen schreiben, könnten Sie eine Proxy-Klasse erstellen, die ein GameState-Objekt übernimmt und nur die Methoden von GameStateInterface implementiert.
%Vor%Dann könnten Sie einen Proxy erstellen und es so übergeben:
%Vor%Der Code, der ein %code% erhält, hätte nur Zugriff auf die Methoden in %code% .
Ich habe ein gesichertes schreibgeschütztes Objekt implementiert. Wenn Sie eine schreibgeschützte Schnittstelle (keine Setter) erstellen, können Sie immer noch Methoden des reinen Objekts typisieren und darauf zugreifen. ZB Interface haben nur ein get und das Kind dieses Interface hat das Set. Wenn Sie das Objekt an die Schnittstelle übergeben, haben Sie nur den get. ABER Sie können immer noch dieses Objekt typisieren und auf alles zugreifen: (
Um dies zu vermeiden, können Sie eine Zusammensetzung erstellen, die NUR dem Ersteller der Klasse gehört. Hier ist ein Beispiel:
%Vor%Auf diese Weise geben Sie Folgendes ein:
%Vor%Er hat also Zugriff auf das Item-Objekt (die innere Klasse kann auf private Methoden zugreifen :)) Wenn Sie nur lesenden Zugriff auf dieses Objekt haben wollen:
%Vor%Nun ist es absolut NICHT möglich, zu tippen, weil sie nicht vom selben Typ sind!
Hoffe, das kann jemandem helfen! (Ich würde gerne, wenn Sie Quelle nennen: P)
Was wir tun, ist ein Jar mit "Stubs", gegen den Sie kompilieren können, aber es enthält keine Implementierung. Wenn das tatsächliche Produkt ausgeführt wird, ersetzen wir die Stubs durch ein echtes Glas.
Aber in unserem Fall kontrollieren wir, wo es läuft.
Auch in unserem Fall machen wir genau das, was Sie verlangen. Jede Klasse muss (zur Laufzeit) Zugriff auf andere Klassen anfordern. Ich glaube, das ist alles eine benutzerdefinierte Implementierung und ich bin mir nicht sicher, ob es auf einer JVM läuft.
Sie können versuchen, den Quellcode für das Zeug, an dem ich gerade arbeite, zu finden / anzufordern. Es gibt eine Referenzimplementierung, wenn Sie angeben, dass Sie an der Entwicklung von Kabelboxen interessiert sind, die Sie möglicherweise erhalten können. Es heißt die "tru2way" oder "OCAP" Referenz-Stack-Implementierung und ich denke, das Projekt ist irgendwo auf der Java-Site verfügbar. Könnte ein bisschen googlen - und ich bin mir ziemlich sicher, dass Sie alles in einem speziellen Klassenlader oder SecurityManager finden.
EDIT: Ich denke, ich könnte falsch liegen. Wir erstellen "Berechtigungen" mit dem Sicherheitsmanager basierend auf dem Namen der Klasse, auf die zugegriffen wird. Wenn ein Thread versucht, eine Methode für die Klasse aufzurufen, testen wir zuerst seine Berechtigungen (wir schreiben den Code innerhalb der Klasse "protected") und wenn der aktuelle Thread nicht über die Berechtigung verfügt, die durch den Namen der Klasse identifiziert wird, löst er ein Ausnahme.
Gleicher Effekt wie später, aber langsamer und ausführlicher. Aber dann müssen wir verhindern, dass Kinder pr0n anschauen.
Bearbeiten 2: (Entschuldigung !!)
Wenn ich auf solche Berechtigungsbeschreibungen schaue, glaube ich, dass es zumindest teilweise möglich ist:
Dadurch wird Codeberechtigung für die Abfrage einer Klasse für ihre öffentlichen, geschützten, standardmäßigen (Paket-) Zugriffs- und privaten Felder und / oder Methoden erteilt. Obwohl der Code Zugriff auf die privaten und geschützten Feld- und Methodennamen hätte, hätte er keinen Zugriff auf die Daten des privaten / geschützten Felds und könnte keine privaten Methoden aufrufen. Dennoch kann bösartiger Code diese Informationen verwenden, um einen Angriff besser zu zielen. Darüber hinaus kann es beliebige öffentliche Methoden aufrufen und / oder auf öffentliche Felder in der Klasse zugreifen. Dies könnte gefährlich sein, wenn der Code normalerweise nicht in der Lage wäre, diese Methoden aufzurufen und / oder auf die Felder zuzugreifen, da er das Objekt nicht mit diesen Methoden und Feldern an die Klasse / Schnittstelle übergeben kann.
Sonst könnten Applets daran gehindert werden, beliebige JVM-Klassen zu instanziieren und darauf zuzugreifen? Es ist möglich, dass die "Gefährlichen" Pfade auf die gleiche Art und Weise blockiert werden, wie wir unsere Sachen blockieren - indem wir die Berechtigungen jedes Mal lesen, wenn sie aufgerufen werden - aber das obige Zitat lässt den Eindruck entstehen, dass mehr verfügbar ist und die meisten Klassen komplett blockiert sind Standard.
Das hat mich eine Weile interessiert, aber ich habe mich nie wirklich darum gekümmert.
Nein, es gibt keine Möglichkeit, dies zu tun.
Beste Wünsche,
Fabian
Man kann nur auf einen zugänglichen Typ umwandeln. Indem Sie GameState privat, paketgeschützt oder geschützt machen, können Sie einschränken, wer darauf casten darf.
Wenn Sie nicht vertrauenswürdigen Code ausführen, müssen Sie einen Sicherheitsmanager installieren, da die Reflektion dazu verwendet werden kann, Zugriffsmodifizierer in der Datei absensce zu umgehen (siehe Feld.setAccessible )
Ich weiß nicht, ob das, was Sie beschreiben, in Java möglich ist. In anderen Sprachen können Sie typecast-Operatoren überlasten und sie eine Exception oder etwas auslösen lassen, aber das ist in Java nicht möglich. Ihre beste Wette ist wahrscheinlich, es auf eine der "vielen anderen Arten" zu tun, über die Sie gesprochen haben.
Ich habe den Code eines einfachen Spiels, in dem ein AgentInterface implementiert werden muss, um einen Agenten-Controller für einen der Charaktere im Spiel zu erstellen. GameState ist eine Klasse, die das GameStateInterface implementiert, und ein Objekt, das diese Schnittstelle implementiert, kann an den Agenten übergeben werden, sodass der Agent die Daten aus dem Spielzustand lesen und analysieren kann und der Agent die entsprechende Aktion (als int zurückgegeben) zurückgeben muss der Charakter sollte nehmen.
Dies ist das AgentInterface, das Agents implementieren müssen:
%Vor%Ausführen des Spiels mit einem Agenten namens MyAgent:
%Vor%Aber es gibt einige Informationen in GameState, auf die der Agent NICHT zugreifen darf, da dies den Controller betrügen würde. Eine Cast-Konvertierung von GameStateInterface in GameState würde es dem Agenten jedoch ermöglichen, auf Informationen zuzugreifen, die nicht im GameStateInterface definiert sind:
%Vor%Meine Frage wäre, ist es möglich, eine Cast-Conversion zu blockieren? Ich weiß, dass Polymorphie eines der Hauptmerkmale von Java und objektorientierten Programmiersprachen ist, aber in solchen Fällen möchte ich Umwandlungen vermeiden.
Ich weiß, dass dies auf viele andere Arten gelöst werden kann, aber ich war neugierig zu wissen, ob es möglich ist, dies zu tun.
Vielen Dank im Voraus.
Soweit ich weiß, ist es nicht möglich, eine Typumwandlung abzufangen und zu leugnen (z. B. durch eine ClassCastException).
Aber anstatt zu versuchen, das Typecase zu leugnen, kannst du einfach das Proxymuster verwenden, um den Zugriff auf den eigentlichen GameState zu kontrollieren Objekt. Implementiere einfach eine Proxy-Klasse, die nur das GameStateInterface implementiert und es alle Methodenaufrufe an das GameState-Objekt weiterleiten lässt. Anstatt den tatsächlichen GameState-Objektverweis an die Aktionsmethode zu übergeben, übergeben Sie ihn nun von einer Instanz Ihrer Proxyklasse umschlossen.
Es ist nicht möglich, einen Cast zu blockieren. Sie können Ihren Spielstatus jedoch so definieren, dass er nur von einem bestimmten Ort aus erstellt werden kann. Eine Sache, die Ihnen in den Sinn kommt, wäre eine private innere Klasse, die die Schnittstelle implementiert, oder eine Factory, die eine private innere Klasseninstanz zurückgibt
Im Allgemeinen können Sie nicht verhindern, dass ein Objekt in Java umgewandelt wird. Der Code, der einen Verweis auf Ihre GameState
erhält, kann eine nicht private, nicht geschützte Methode für dieses Objekt aufrufen. Selbst wenn Sie Casting verhindern könnten, könnte es immer noch Reflexion verwenden.
Wenn der Agent
-Code unter Ihrer Kontrolle steht, halten Sie die Dinge einfach und werfen Sie sie nicht um. Wenn andere Agent
-Klassen schreiben, könnten Sie eine Proxy-Klasse erstellen, die ein GameState-Objekt übernimmt und nur die Methoden von GameStateInterface implementiert.
Dann könnten Sie einen Proxy erstellen und es so übergeben:
%Vor% Der Code, der ein GameStateProxy
erhält, hätte nur Zugriff auf die Methoden in GameStateInterface
.
Wenn Sie Bedenken haben, dass der Spielstatus von einem Agenten geändert wird, erstellen Sie eine Bean-Kopie des Status und übergeben Sie diese an den Agenten und nicht an das echte GameState-Objekt.
Es ist nicht möglich, einen Cast zu verbieten (es ist wahrscheinlich eine nicht sperrbare JVM-Sprachspezifikation), oder ich habe noch nie davon gehört.
Ich habe ein gesichertes schreibgeschütztes Objekt implementiert. Wenn Sie eine schreibgeschützte Schnittstelle (keine Setter) erstellen, können Sie immer noch Methoden des reinen Objekts typisieren und darauf zugreifen. ZB Interface haben nur ein get und das Kind dieses Interface hat das Set. Wenn Sie das Objekt an die Schnittstelle übergeben, haben Sie nur den get. ABER Sie können immer noch dieses Objekt typisieren und auf alles zugreifen: (
Um dies zu vermeiden, können Sie eine Zusammensetzung erstellen, die NUR dem Ersteller der Klasse gehört. Hier ist ein Beispiel:
%Vor%Auf diese Weise geben Sie Folgendes ein:
%Vor%Er hat also Zugriff auf das Item-Objekt (die innere Klasse kann auf private Methoden zugreifen :)) Wenn Sie nur lesenden Zugriff auf dieses Objekt haben wollen:
%Vor%Nun ist es absolut NICHT möglich, zu tippen, weil sie nicht vom selben Typ sind!
Hoffe, das kann jemandem helfen! (Ich würde gerne, wenn Sie Quelle nennen: P)
Was wir tun, ist ein Jar mit "Stubs", gegen den Sie kompilieren können, aber es enthält keine Implementierung. Wenn das tatsächliche Produkt ausgeführt wird, ersetzen wir die Stubs durch ein echtes Glas.
Aber in unserem Fall kontrollieren wir, wo es läuft.
Auch in unserem Fall machen wir genau das, was Sie verlangen. Jede Klasse muss (zur Laufzeit) Zugriff auf andere Klassen anfordern. Ich glaube, das ist alles eine benutzerdefinierte Implementierung und ich bin mir nicht sicher, ob es auf einer JVM läuft.
Sie können versuchen, den Quellcode für das Zeug, an dem ich gerade arbeite, zu finden / anzufordern. Es gibt eine Referenzimplementierung, wenn Sie angeben, dass Sie an der Entwicklung von Kabelboxen interessiert sind, die Sie möglicherweise erhalten können. Es heißt die "tru2way" oder "OCAP" Referenz-Stack-Implementierung und ich denke, das Projekt ist irgendwo auf der Java-Site verfügbar. Könnte ein bisschen googlen - und ich bin mir ziemlich sicher, dass Sie alles in einem speziellen Klassenlader oder SecurityManager finden.
EDIT: Ich denke, ich könnte falsch liegen. Wir erstellen "Berechtigungen" mit dem Sicherheitsmanager basierend auf dem Namen der Klasse, auf die zugegriffen wird. Wenn ein Thread versucht, eine Methode für die Klasse aufzurufen, testen wir zuerst seine Berechtigungen (wir schreiben den Code innerhalb der Klasse "protected") und wenn der aktuelle Thread nicht über die Berechtigung verfügt, die durch den Namen der Klasse identifiziert wird, löst er ein Ausnahme.
Gleicher Effekt wie später, aber langsamer und ausführlicher. Aber dann müssen wir verhindern, dass Kinder pr0n anschauen.
Bearbeiten 2: (Entschuldigung !!)
Wenn ich auf solche Berechtigungsbeschreibungen schaue, glaube ich, dass es zumindest teilweise möglich ist:
Dadurch wird Codeberechtigung für die Abfrage einer Klasse für ihre öffentlichen, geschützten, standardmäßigen (Paket-) Zugriffs- und privaten Felder und / oder Methoden erteilt. Obwohl der Code Zugriff auf die privaten und geschützten Feld- und Methodennamen hätte, hätte er keinen Zugriff auf die Daten des privaten / geschützten Felds und könnte keine privaten Methoden aufrufen. Dennoch kann bösartiger Code diese Informationen verwenden, um einen Angriff besser zu zielen. Darüber hinaus kann es beliebige öffentliche Methoden aufrufen und / oder auf öffentliche Felder in der Klasse zugreifen. Dies könnte gefährlich sein, wenn der Code normalerweise nicht in der Lage wäre, diese Methoden aufzurufen und / oder auf die Felder zuzugreifen, da er das Objekt nicht mit diesen Methoden und Feldern an die Klasse / Schnittstelle übergeben kann.
Sonst könnten Applets daran gehindert werden, beliebige JVM-Klassen zu instanziieren und darauf zuzugreifen? Es ist möglich, dass die "Gefährlichen" Pfade auf die gleiche Art und Weise blockiert werden, wie wir unsere Sachen blockieren - indem wir die Berechtigungen jedes Mal lesen, wenn sie aufgerufen werden - aber das obige Zitat lässt den Eindruck entstehen, dass mehr verfügbar ist und die meisten Klassen komplett blockiert sind Standard.
Das hat mich eine Weile interessiert, aber ich habe mich nie wirklich darum gekümmert.
Man kann nur auf einen zugänglichen Typ umwandeln. Indem Sie GameState privat, paketgeschützt oder geschützt machen, können Sie einschränken, wer darauf casten darf.
Wenn Sie nicht vertrauenswürdigen Code ausführen, müssen Sie einen Sicherheitsmanager installieren, da die Reflektion dazu verwendet werden kann, Zugriffsmodifizierer in der Datei absensce zu umgehen (siehe Feld.setAccessible )
Ich weiß nicht, ob das, was Sie beschreiben, in Java möglich ist. In anderen Sprachen können Sie typecast-Operatoren überlasten und sie eine Exception oder etwas auslösen lassen, aber das ist in Java nicht möglich. Ihre beste Wette ist wahrscheinlich, es auf eine der "vielen anderen Arten" zu tun, über die Sie gesprochen haben.
Normalerweise mache ich:
%Vor%Bei Bedarf schnelle 3-Version:
%Vor%Ok, tut mir leid, als wäre ich durch meinen Code gegangen.
Ich habe den Indikator folgendermaßen beendet:
%Vor%Nach einem Durchlauf wurde der activityIndicator vollständig entfernt.
Diese Frage ist sehr nützlich. Aber eine Sache, die in der Antwort fehlt, ist, dass alles, was lange braucht, in einem separaten Thread ausgeführt werden muss, nicht die UIActivityIndicatorView. Auf diese Weise reagiert es nicht mehr auf die Benutzeroberfläche.
%Vor%Alle UI-Elemente müssen sich im Haupt-Thread befinden
%Vor%dann:
%Vor%Wenn ich startAnimating für eine UIActivityIndicatorView aufruft, wird sie nicht gestartet. Warum ist das?
[Dies ist eine Blog-artige selbstbeantwortete Frage. Die Lösung unten funktioniert für mich, aber vielleicht gibt es andere, die besser sind?]
Wenn Sie Code wie folgt schreiben:
%Vor%Sie erteilen der Benutzeroberfläche keine Zeit, um den Aktivitätsindikator tatsächlich zu starten und zu stoppen, da sich Ihre gesamte Berechnung auf den Hauptthread bezieht. Eine Lösung besteht darin, startAnimating in einem separaten Thread aufzurufen:
%Vor%Oder Sie könnten Ihre Berechnung in einen separaten Thread einfügen und warten, bis sie beendet ist, bevor Sie stopAnimation aufrufen.