You can add a public
nested interface to Class1
with default
methods which call their respective package-access methods in Class1
and implement
that interface in Class2
so that only Class2
gains access to Class1
's package-access methods through that interface (sorry!).
Probably better at this point to show the code.
Class1
I added some dumb printing implementation for the method to show that it is being called properly.
package package1;
public class Class1 {
int i;
public Class1(int i) {
this.i = i;
}
// Utility method only for Class2
void performUtilityOperation() {
System.out.println(i);
}
public interface Mediator {
default void performUtilityOperation(Class1 c1) {
c1.performUtilityOperation();
}
}
// other public methods...
}
The interface defines a default
method, which given an instance of Class1
, calls that instance's respective method. I used the same names for the enclosing class and interface methods, but they can be different.
Note that the interface must be public
itself, so it can be visible to Class2
for implementation.
Class2
package package2;
import package1.Class1;
public class Class2 implements Class1.Mediator {
Class1 class1;
public void setClass1(Class1 class1) {
this.class1 = class1;
}
public void doSomeOperation() {
performUtilityOperation(class1);
}
// other public methods
}
Implementing the interface allows access to its default
methods. Since Class2
holds an instance of Class1
, it is (to be) used in all invocations of the interface methods. The interface delegates the operations to the Class1
instance.
UserClass
I added this class in its own package as a place to instantiate the classes and call the various methods. I'm not sure how it is intended to be done in your case, but ironing out the details should not be a problem.
package user;
import package1.Class1;
import package2.Class2;
class UserClass {
public static void main(String[] args) {
Class1 clazz1Int3 = new Class1(3);
Class1 clazz1Int4 = new Class1(4);
Class2 c2 = new Class2();
c2.setClass1(clazz1Int3);
c2.doSomeOperation();
c2.setClass1(clazz1Int4);
c2.doSomeOperation();
// clazz1Int3.performUtilityOperation(); // The method performUtilityOperation() from the type Class1 is not visible
}
}
I instantiate 2 Class1
s with a different int
just to distinguish between them easily. I then use your given method to set the Class1
reference in Class2
and call the public
(exposed to the user) method in Class2
. This call, inside it, calls the non-accessible (non-visible) utility method in Class1
through the Mediator
interface.
Note that the only way to access Class1
's utility method outside of its package is to implement Mediator
(you can't call it from Mediator
itself because you can't instantiate an interface). Since only Class2
does that (and you can control which other classes do it as well, if at all), only it can access it outside of Class1
's package.
The output for running the above is
3
4
Why the nested interface?
Actually, you don't have to put the interface as a nested interface - it depends on your overall structure. It can reside in its own compilation unit, but in the same package as Class1
so it will have the (package access) utility methods visible. The advantage of it being a nested interface is that now the utility methods can actually be private
(or protected
) and thus not even accessible in their package.
I mention this because you specify
I want to add few utility methods in class1 that only class2 can access.
but it is not clear if you mean "only class2 can access outside of class1's package" or "only class2 can access overall". You made the utility method package-access, so it hints to the first option, but I wasn't sure.
There is also the design consideration of "is this the right place to put this interface?", but I can't know that - you can. Nested interfaces generally follow the same design considerations a nested classes, so you have that to rely upon.
Final note
If it was not obvious, then this approach is preferred to extending classes since that restricts your inheritance, while implementing interfaces is "free" in that regard.