11

Java (C++ など) でフレンドの概念をどのように実装しますか?

4

4 に答える 4

34

Java には、C++ のフレンド キーワードはありません。ただし、それをエミュレートする方法があります。実際にはより正確な制御を提供する方法です。クラス A と B があるとします。B は、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);
    }
}

usageExample() は、これがどのように機能するかを示しています。B のインスタンスは、A のインスタンスのプライベート フィールドまたはメソッドにアクセスできません。しかし、giveKeyTo() を呼び出すことにより、クラス B はアクセスを取得できます。引数として有効な B が必要なため、他のクラスはそのメソッドにアクセスできません。コンストラクターはプライベートです。

クラス B は、キーで渡された任意のメソッドを使用できます。これは、C++ の friend キーワードより設定が面倒ですが、はるかにきめ細かく設定できます。クラス A は、どのメソッドをどのクラスに公開するかを正確に選択できます。

上記のケースでは、A は B のすべてのインスタンスと B のサブクラスのインスタンスへのアクセスを許可しています。後者が望ましくない場合、giveKeyTo() メソッドは getClass() を使用して other の正確なタイプを内部的にチェックし、throw します。正確に B でない場合は例外です。

于 2013-01-09T00:02:48.440 に答える
6

によってのみ呼び出さA.foo()れるとしBます。これは、 によってのみ生成できるトークンによって調整できますB

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");
        // ...
    }
}

Bnull 以外のB.ToAトークンのみを生成できます。Aとの両方Bがこのトークンをサードパーティに漏らさない場合、他の誰も呼び出すことができませんA.foo()

A2友達になりたい場合Bは、別のトークン タイプが必要です。同じトークン タイプの場合、 は からAタイプのトークンを取得したため、 のBふりAをすることができBますA2

チェックはコンパイル時ではなく実行時に行われるため、完全ではありません。ただし、大したことではありません。サードパーティは でしか呼び出すことA.foo()nullできないため、コンパイル時にチェックしたい無害な間違いではありません。おそらく悪意があるため、コンパイル時に呼び出し元に警告する必要はありません。

于 2013-01-09T02:47:55.200 に答える
1

Java では、両方 (またはそれ以上) のクラスを同じパッケージに入れることができます。修飾子を持つすべてのメソッドとフィールドは、protectedそのパッケージ内のすべてのクラスから直接アクセスできます。

于 2013-01-09T00:09:40.033 に答える
-2

同じことを達成する別の方法を考え出しました。基本的に、呼び出しクラス名の完全修飾名を確認します。「フレンド」関数と一致する場合はアクセスを許可し、それ以外の場合は null を返します。

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);
    }
}
于 2013-01-09T01:59:54.717 に答える