我有一个包含两个软件包的库项目,分别是package1和package2,分别是class1和class2。 class1有一些公共方法暴露给最终用户。我想在class1中添加一些只有class2才能访问的实用方法。我搜索了很多,但我找不到任何访问修饰符,只能在同一个项目的不同包中授予访问权限。
有没有机会以任何方式实现它?
更新(代码示例):
package1中的Class1:
package com.example.package1;
public class Class1 {
// This method should only be accessed by Class2, cannot made it public for
// every class
void performUtilityOperation() {
// internal utility
}
// other public methods...
}
package2中的Class2:
package com.example.package2;
import com.example.package1.*;
public class Class2 {
Class1 class1;
public void setClass1(Class1 class1) {
this.class1 = class1;
}
public void doSomeOperation() {
this.class1.performUtilityOperation(); // here this method is not
// accessible if not public
// do some other operations
}
// other public methods
}
答案 0 :(得分:2)
没有办法实现这一点(如果你来自哪里,那就像C ++中的friend
一样)。虽然protected
成员可以通过扩展类从不同的包访问,如下所示:
package1
public Class1{
protected method();
}
Class2 extends Class1
因此即使Class2位于不同的包中,method()
也会显示Class1
。
package2
public Class2 extends Class1{
public otherMethod(){
method(); // is visible here
}
}
Class3
未展开Class1
,因此method()
将不可见
package2
public Class3{
public otherMethod(){
method(); // not visible here
}
}
IMO这是您在Class1
中隐藏方法的最远距离答案 1 :(得分:2)
您可以使用public
方法向Class1
添加default
嵌套接口,这些方法在Class1
和implement
中调用各自的包访问方法Class2
这样只有Class2
才能通过该界面访问Class1
的包访问方法(抱歉!)。
此时可能更好地展示代码。
Class1
我为该方法添加了一些哑打印实现,以显示它被正确调用。
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...
}
接口定义了一个default
方法,该方法给出了Class1
的实例,调用该实例的相应方法。我对封闭类和接口方法使用了相同的名称,但它们可以不同。
请注意,界面必须是public
本身,因此Class2
可以看到该界面的实现。
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
}
实现接口允许访问其default
方法。由于Class2
包含Class1
的实例,因此它将(将)用于接口方法的所有调用。接口将操作委托给Class1
实例。
UserClass
我在自己的包中添加了这个类作为实例化类并调用各种方法的地方。我不确定在你的情况下是怎么做的,但是熨平细节应该不是问题。
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
}
}
我使用不同的Class1
实例化2 int
只是为了轻松区分它们。然后,我使用您的给定方法在Class1
中设置Class2
引用,并在public
中调用 Class2
(向用户公开)方法。其中的此调用通过Class1
接口调用Mediator
中的不可访问(不可见)实用程序方法。
请注意,在其软件包之外访问Class1
实用程序方法的唯一方法是实现Mediator
(您无法从{{1}调用它本身,因为你无法实例化一个接口)。由于只有Mediator
这样做(并且您可以控制哪些其他类也可以,如果有的话),只有它可以在Class2
的包之外访问它。
运行上述内容的输出是
Class1
实际上,您不必将接口作为嵌套接口 - 它取决于您的整体结构。它可以驻留在自己的编译单元中,但与3
4
位于同一个包中,因此它可以看到(包访问)实用程序方法。它作为嵌套接口的优点是,现在实用程序方法实际上可以是Class1
(或private
),因此甚至无法在其包中访问。
我提到这是因为你指定了
我想在class1中添加一些只有class2才能访问的实用方法。
但不清楚你的意思是“只有class2可以访问class1的包之外”或“只有class2可以访问整体”。您使用了实用程序方法package-access,因此它提示第一个选项,但我不确定。
还有设计考虑“这是放置这个界面的正确位置吗?”,但我不知道 - 你可以。嵌套接口通常遵循嵌套类的相同设计考虑因素,因此您可以依赖它。
如果不明显,那么这种方法比扩展类更受欢迎,因为这限制了你的继承,而实现接口在这方面是“免费的”。
答案 2 :(得分:0)
我将以下解决方法放在一起,确保只有指定的包可以访问某些方法:
public class Reserved {
private static Package p = AccesserA.class.getPackage();
public void doSomething() throws ClassNotFoundException {
if (p.equals(Class.forName(Thread.currentThread().getStackTrace()[2].getClassName()).getPackage())) {
System.out.println("Access granted");
} else {
System.out.println("Access denied");
}
}
public static void doSometingElse() throws ClassNotFoundException {
if (p.equals(Class.forName(Thread.currentThread().getStackTrace()[2].getClassName()).getPackage())) {
System.out.println("Access granted");
} else {
System.out.println("Access denied");
}
}
}
如您所见,您指定Package p
作为允许访问的包。在方法调用doSometing()
或doSometingElse()
时,将根据允许的包检查调用类的包。如果相等,则打印Access granted
,否则打印Access denied
。您可以创建一个实现此功能的abstract
类,并且每个需要受限访问的类都可以简单地扩展它并提供允许的包。它也适用于静态方法。
让我们创建两个试图访问Reserved
方法的类:
package a.b.c;
public class AccesserA {
public void tryAccess() throws ClassNotFoundException {
Reserved res = new Reserved();
res.doSomething();
}
}
和
package a.b;
public class AccesserB {
public void tryAccess() throws ClassNotFoundException {
Reserved res = new Reserved();
res.doSomething();
Legit.Reserved.doSometingElse();
}
}
主:
public static void main (String ... args) throws IOException, InterruptedException, ClassNotFoundException {
AccesserA a = new AccesserA();
AccesserB b = new AccesserB();
a.tryAccess();
b.tryAccess();
}
这将产生输出:
Access granted
Access denied
Access denied
答案 3 :(得分:0)
如果您甚至不希望用户看到该方法,则必须创建一个Facade(公共接口)并仅公开此Facade。不要让用户直接使用实现类。
这通常使用工厂或工厂方法+(如果您愿意)将所有敏感构造函数设为私有。
public class Class1 implements Interface1 {
private Class1() {}
public static Interface1 create() { return new Class1(); }
// This method is not visible through Interface1
public void performUtilityOperation() {
// internal utility
}
}
然后,无论您想使用实用程序方法,都必须使用强制转换:
Interface1 class1_instance = Class1.create();
((Class1) class1_instance).performUtilityOperation();
如果你想要某种安全性(请注意,通常可以使用反射来破解它),然后将其与其他答案/评论中建议的解决方案结合起来......