web-dev-qa-db-ja.com

Javaでのフレンドコンセプトの実装

Java(C++のように)で友達の概念をどのように実装しますか?

8
Alastor Moody

Javaには、C++のfriendキーワードがありません。ただし、それをエミュレートする方法があります。実際にはるかに正確な制御を提供する方法。クラス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()を使用して他の正確なタイプを内部的にチェックし、スローすることができます。正確にBでない場合の例外。

29
Alastor Moody

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

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

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

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

5
irreputable

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

1
AlexWien