我有两个包:
1. com.test.hidden
:
包含一个 protected 接口(interface)MyListener
和一个公共(public)类FancyClass
,其中包含用于注册MyListener
对象的公共(public)方法:
package com.test.hidden;
public class FancyClass {
public void registerListener(MyListener listener) {
// ...
}
}
<小时/>
package com.test.hidden;
interface MyListener {
void doSomething();
}
2. com.test.myapp
:
这里我有一个 FancyClass
实例,我想向它注册一个新的 MyListener
对象。
显然这不会起作用,因为 MyListener
在 com.test.myapp
中不可见。我的直觉是在 com.test.hidden
中创建一个新接口(interface),该接口(interface)扩展了 MyListener
并且是公共(public)的:
package com.test.hidden;
public interface MyListenerWrapper extends MyListener {
@Override
void doSomething();
}
<小时/>
package com.test.myapp
import com.test.hidden.FancyClass
import com.test.hidden.MyListenerWrapper
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
val fc = FancyClass()
fc.registerListener(object : MyListenerWrapper {
override fun doSomething() {
// ...
}
})
}
}
但是我收到一个IllegalAccessError
:
java.lang.IllegalAccessError: Illegal class access: 'com.test.myapp.MainActivity' attempting to access 'com.test.hidden.MyListener' (declaration of 'com.test.myapp.MainActivity' appears in /data/app/com.test.myapp-ZzNlHhuBCCdAEV4QsZHspw==/base.apk)
at com.test.myapp.MainActivity.onCreate(MainActivity.kt:15)
at android.app.Activity.performCreate(Activity.java:7136)
at android.app.Activity.performCreate(Activity.java:7127)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1272)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2899)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3054)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1814)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:280)
at android.app.ActivityThread.main(ActivityThread.java:6710)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
当我将 MyListener
的可见性更改为 public 时,它工作得很好,所以我怀疑 Java 不喜欢增加子接口(interface)中接口(interface)的可见性。为什么这不起作用以及如何解决这个问题?
最佳答案
Kotlin 不喜欢在公共(public)方法中公开内部 API,如果这样做,实际上甚至会给出编译器错误。如果您从 Kotlin 调用代码,这也会影响 Java 代码,但它会在运行时而不是编译时引发异常。
至于解决方案,Kotlin 有 internal
,但这是一个非常特殊的关键字:与 Java 的包 private(无修饰符)不同,internal 使其在模块中的任何地方都可见。
这也是一种解决方案:转换为 Kotlin 并使用 internal
。如果您正在创建一个库,它在模块外部将不可见,但您至少可以在内部声明它。
第二个是将接口(interface)转换为类并使用密封类
。请注意,这要求所有子级都在同一个文件中声明。请参阅this有关密封类的更多信息。
最终的解决方案:公开。我强烈建议您选择此选项而不是其他选项,主要是因为它是最简单的选项,并且不需要黑客设计。另外,如果您计划在其他地方访问该接口(interface),则必须使用特定的实现而不是通用的父类(super class),这并不总是可行的(不过取决于您的使用情况)。
还有只使用 Java 的选项,但我认为您更喜欢混合,因为您已经这样做了。但如 Michael mentioned ,你真的应该避免这种设计:这是糟糕的设计。如果我是你,无论如何我都会将其公开。
关于java - 增加界面的可视性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54912499/