Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementation of Friend concept in Java [duplicate]

How does one implement the friend concept in Java (like C++)?

like image 440
FirstName LastName Avatar asked Jan 09 '13 00:01

FirstName LastName


2 Answers

Java does not have the friend keyword from C++. There is, however, a way to emulate that; a way that actually gives a lot more precise control. Suppose that you have classes A and B. B needs access to some private method or field 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);
    }
}

The usageExample() shows how this works. The instance of B doesn't have access to the private fields or methods of an instance of A. But by calling the giveKeyTo(), class B can get access. No other class can get access to that method, since it a requires a valid B as an argument. The constructor is private.

The class B can then use any of the methods that are handed to it in the key. This, while clumsier to set up than the C++ friend keyword, is much more fine-grained. The class A can chose exactly which methods to expose to exactly which classes.

Now, in the above case A is granting access to all instances of B and instances of subclasses of B. If the latter is not desired, then the giveKeyTo() method can internally check the exact type of other with getClass(), and throw an exception if it is not precisely B.

like image 78
FirstName LastName Avatar answered Oct 18 '22 14:10

FirstName LastName


Suppose A.foo() should only be called by B. This can be arranged by a token that can only be generated by 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");
        // ...
    }
}

Only B can generate a non-null B.ToA token. If both A and B do not leak this token to the 3rd party, nobody else can invoke A.foo()

If A2 wants to friend B too, it needs a different token type. If it's the same token type, since A got a token of the type from B, A can pretend to be B to A2.

The check is done at runtime, not compile time, that is not perfect. Not a big deal though, since any 3rd party can only invoke A.foo() with a null, it can't be an innocent mistake which we want to check at compile time; it's probably malicious so we don't care to warn the caller at compile time.

like image 43
irreputable Avatar answered Oct 18 '22 12:10

irreputable