2013-01-09 14 views
5

Wie implementiert man das Friend-Konzept in Java (wie C++)?Implementierung des Friend-Konzepts in Java

+0

Auch wenn ich in C++ code, benutze ich 'Freund' extrem sparsam, wenn überhaupt. Die Bereitstellung einer öffentlichen Schnittstelle, die von allen genutzt werden kann, ist viel sicherer. –

+0

Ich habe kein Freund-Konzept in Java in meinem Code verwendet. Ich war neugierig nur um der Neugier willen. –

+0

@ Code-Guru Wie würde eine öffentliche Schnittstelle helfen? Ich könnte hier etwas verpassen. Kannst du einen Link mit mehr Details posten? –

Antwort

23

Java hat das Friend-Schlüsselwort aus C++ nicht. Es gibt jedoch eine Möglichkeit, das zu emulieren; ein Weg, der tatsächlich viel genauere Kontrolle gibt. Nehmen wir an, dass Sie die Klassen A und B. B benötigt Zugriff auf einige private Methode oder ein Feld in A.

public class A { 
    private int privateInt = 31415; 

    public class SomePrivateMethods { 
     public int getSomethingPrivate() { return privateInt; } 
     private SomePrivateMethods() { } // no public constructor 
    } 

    public void giveKeyTo(B other) { 
     other.receiveKey(new SomePrivateMethods()); 
    } 
} 

public class B { 
    private A.SomePrivateMethods key; 

    public void receiveKey(A.SomePrivateMethods key) { 
     this.key = key; 
    } 

    public void usageExample() { 
     A anA = new A(); 

     // int foo = anA.privateInt; // doesn't work, not accessible 

     anA.giveKeyTo(this); 
     int fii = key.getSomethingPrivate(); 
     System.out.println(fii); 
    } 
} 

Die usageExample() zeigt, wie das funktioniert haben. Die Instanz von B hat keinen Zugriff auf die privaten Felder oder Methoden einer Instanz von A. Durch den Aufruf von giveKeyTo() kann Klasse B jedoch Zugriff erhalten. Keine andere Klasse kann auf diese Methode zugreifen, da sie ein gültiges B als Argument benötigt. Der Konstruktor ist privat.

Die Klasse B kann dann alle Methoden verwenden, die ihr im Schlüssel übergeben werden. Dies ist zwar viel schwieriger einzurichten als das C++ - Friend-Keyword, ist aber viel feinkörniger. Die Klasse A kann genau auswählen, welche Methoden genau welchen Klassen zugänglich gemacht werden sollen.

Jetzt gewährt A Zugriff auf alle Instanzen von B und Instanzen von Unterklassen von B. Wenn letzteres nicht gewünscht ist, kann die giveKeyTo() -Methode intern den genauen Typ des anderen mit getClass überprüfen () und eine Exception auslösen, wenn sie nicht genau B ist.

+0

Sehr schön. Ein besserer Weg, dies zu implementieren, wäre vielleicht, die Klasse "B" als "endgültig" zu deklarieren, um mögliche Sicherheitsrisiken zu vermeiden. – user991710

1

In Java können Sie beide (oder mehr) Klassen in dasselbe Paket einfügen. Alle Methoden und Felder mit dem Qualifier protected können von allen Klassen in diesem Paket direkt aufgerufen werden.

+0

Tatsächlich jedoch, wenn es bereits bestehende Legacy-Code in Ort und Refactoring wird einen Streit sein und Sie nicht möchten, dass die Sichtbarkeit von Feldern und Methoden ändern, dann so einen Freund fuctionality Einrichtung könnte eine Option sein. Ich stimme zu, es wird nicht gut lesbar sein oder sogar empfohlen, aber es funktioniert wie eine schnelle Lösung. –

+0

ich das Bedürfnis, dieser einen letzten Graben, darauf hinzuweisen, aus Optionen, schlimmster Fall, willkommen zu Subprime-Niveau an technischen Schulden, wenn es permanent temporären werden oder vorübergehend dauerhafte Option. –

+0

Fast alle Leute, die ich kenne würde nur die betroffenen Methoden wie öffentlich definieren, aber Ihr Ansatz ist interessant – AlexWien

-2

Ich fand einen anderen Weg, um das gleiche zu erreichen. Grundsätzlich überprüfen Sie den voll qualifizierten Namen des aufrufenden Klassennamens. Wenn es mit Ihrer "Freund" -Funktion übereinstimmt, geben Sie Zugriff, sonst geben Sie null zurück.

public class A { 
    private static int privateInt = 31415; 

    public static int getPrivateInt() { 
     if(Throwable().getStackTrace()[1].getClassName().equals(new String("example.java.testing.B"))) 
     { 
     return privateInt; 
     } 
     else 
     { 
     return null; 
     } 
    } 
} 


package example.java.testing; 
public class B { 

public void usageExample() { 
    int foo = A.getPrivateInt; // works only for B 
    System.out.println(foo); 
    } 
} 
3

Angenommen A.foo() sollte nur von B aufgerufen werden. Dies kann durch ein Token arrangiert werden, das nur von B erzeugt werden kann.

public class B 
{ 
    public static class ToA { private ToA(){} } 
    private static final ToA b2a = new ToA(); 

    void test() 
    { 
     new A().foo(b2a); 
    } 
} 

public class A 
{ 
    public void foo(B.ToA b2a) 
    { 
     if(b2a==null) 
      throw new Error("you ain't B"); 
     // ... 
    } 
} 

Nur B kann eine Nicht-Null-B.ToA Token generieren. Wenn beide A und B nicht dieses Token an die dritte Partei austreten kann sonst niemand A.foo()

aufrufen Wenn A2 an Freund will B auch, braucht es einen anderen Token-Typ. Wenn es sich um den gleichen Tokentyp handelt, kann A ein Token des Typs B erhalten, A kann als B bis A2 vorgeben.

Die Überprüfung erfolgt zur Laufzeit, nicht zur Kompilierzeit, das ist nicht perfekt. Keine große Sache, da jeder Dritte nur A.foo() mit einem null aufrufen kann, kann es kein unschuldiger Fehler sein, den wir zur Kompilierzeit überprüfen möchten; Es ist wahrscheinlich bösartig, daher ist es nicht wichtig, den Aufrufer zur Kompilierzeit zu warnen.