Class-specific method visibility

2019-07-18 15:10发布

问题:

Is there some object oriented thing that you can call some methods from certain classes, but not all of them? Is there something like that which is similiar to protected?

Say you have a method void foo() and you want it to be available to the programmer in a few types of classes (perhaps something like using Type variables (to specify: T type). Now, perhaps is there some way, without inheriting the class with foo() in it, or making an interface, to specify which classes or types of classes have access to that method?

I would guess this could be like multiple-inheritance and polymorphism? But I still want only the class and certain classes to access the method without changing the visibility of the method. I want the visibility to be class-specific.

Here is an example:

class A sees foo() as private, but only that class sees it as private.
class B sees foo() as public/protected, but only that class sees it as public.

The method type would be default.

I guess what is easier to ask and answer to is: "Is there class-specific visibility?"

回答1:

There is something like you are asking for in C++, it is called friend classes. Nevertheless, that concept is not supported by Java:

'Friends' equivalent for Java?

A second option is to use code reflection to access a class private members but it isn't such a clean solution and only works for protected elements:

public class C1 {

    public C1()
    {
        x = "Hello Word!";
    }

    protected String x;
}

At a different class's method:

String val = (String)obj.getClass().getDeclaredField("x").get(obj);
System.out.println("val: " + val);

EDIT: After making a little bit of research I found it is possible even to access private members:

Field field = obj.getClass().getDeclaredField("x");
field.setAccessible(true);
String val = (String)field.get(obj);
field.setAccessible(false);


回答2:

No, there's nothing like that in Java.

The closest you've got is putting classes within the same package, at which point they have access to any members which don't specify any access modifier. You can't specify particular classes though.

Another option which is appropriate in some cases is to use nested classes:

class Outer {
    private static class Inner {
    }
}

Here Outer and Inner have access to each other's private members.



回答3:

Access Levels

Modifier    Class   Package Subclass  World
public       Y        Y       Y        Y
protected    Y        Y       Y        N
no modifier  Y        Y       N        N
private      Y        N       N        N

thats your lot, there are not any other access modifiers.



回答4:

With a little sleight of hand you can make one class seem to be two different classes:

// An interface.
interface A {
    public void a ();
}

// Another interface.
interface B {
    public void b ();
}

// Deliberately NOT stating we implement either A or B but actually we implement both.
class C {
    public void a () {

    }
    public void b () {

    }
}

// Pick either implementation from C and tell the world about it.
class D extends C implements A {
    // Do nothing - already done by C.
}

class E extends C implements B {
    // Do nothing - already done by C.
}

public void test() {
    A d = new D();
    B e = new E();
}

Here D and E are actually identically functioned objects because they are both actually Cs. However, as they are created they are made to seem to be A or B which are two different interfaces.

Unfortunately we cannot hide the fact that they both extend C but a little further sleight of hand and we can do that too with a Factory.

// Hide the guts of it all in a factory.
static class Factory {
    // Make sure you MUST use the factory methods.
    private Factory () {

    }

    // Construct an A.
    public static A newA () {
        return new D();
    }

    // Construct a B.
    public static B newB () {
        return new E();
    }
}