如何实现SDK内部类无需设为private即可仅库内访问、对App不可见
SDK类拆分对外隐藏实现的可行方案
针对你要对外暴露External、隐藏全量实现类Internal同时支持SDK内部跨模块访问的需求,以下是工业界SDK开发常用的实现方案,不需要把Internal设为私有类:
方案1:包路径隔离 + JPMS模块定向导出(Java 9+ 首选,无额外开销)
这是Java生态SDK开发的标准实现方案,完全没有额外抽象层,性能零损耗:
- 按访问权限拆分包路径:把需要对外暴露的
External类放在公开API包下(例如com.your.sdk.api),把Internal实现类放在内部专属包下(例如com.your.sdk.internal.model) Internal类不需要加private修饰,直接声明为public即可,类定义如下:
// 位于com.your.sdk.internal.model包 public class Internal extends External { public String internal1; public String internal2; }
- 在SDK的
module-info.java中做导出控制:仅对外导出公开API包,内部包只定向给SDK自身的模块开放访问权限,外部App完全无法引用内部包下的任何类:
module your.sdk.core { // 对外仅暴露api包,接入方只能访问External类 exports com.your.sdk.api; // 内部包定向导出给SDK的其他内部模块,支持跨模块访问Internal exports com.your.sdk.internal.model to your.sdk.module1, your.sdk.module2; }
这种实现下,Internal作为全量类完全替代原有Everything的能力,SDK内部可以直接访问其所有成员,外部App连Internal类的符号都无法获取,自然不可能访问或实例化该类。
方案2:公开抽象类/接口 + 内部实现(兼容Java 8及更低版本)
如果需要兼容不支持JPMS的环境(例如旧版Android、Java 8 runtime),可以用API和实现隔离的写法:
- 把对外暴露的
External定义为public接口或者抽象类,只声明需要对外暴露的字段访问方法、公共能力,不包含任何内部字段:
// 对外公开的API定义 public abstract class External { public abstract String getExternal1(); public abstract String getExternal2(); }
Internal作为External的具体实现类,放在内部非公开包下,声明为public,持有所有全量字段:
// 位于内部包,外部无法直接引用 public class Internal extends External { public String external1; public String external2; public String internal1; public String internal2; @Override public String getExternal1() { return external1; } @Override public String getExternal2() { return external2; } }
- 所有对外返回的对象都向上转型为
External类型,外部App只能调用External定义的公开方法,即使尝试强转也会因为找不到Internal类抛出ClassNotFoundException;SDK内部可以直接用Internal类型访问所有字段,跨模块访问没有权限限制。
注意事项
- 不要用private嵌套类实现
Internal:private嵌套类的访问范围仅限宿主类内部,跨模块访问需要写大量反射或者桥接方法,维护成本极高 - 不要依赖类加载器或者反射做隐藏:稳定性差,容易被反射绕过,后续JDK版本升级会有兼容性问题
内容的提问来源于stack exchange,提问作者Zoose
相关产品推荐
相关产品推荐

