Java 具有默认(包)可见性覆盖的Android方法(不应该工作,但是为什么?)

Java 具有默认(包)可见性覆盖的Android方法(不应该工作,但是为什么?),java,android,inheritance,svg,android-resources,Java,Android,Inheritance,Svg,Android Resources,我一直在玩Android中的SVG支持,并提出了一个库,声称它支持SVG,就像它是本地的一样 因为我费了很大的劲才发现这是不可能的,所以我去看看这个家伙是怎么做到的。所以我找到了他的方法,他在其中声明了一个方法(loadDrawable),该方法在基本资源类中具有默认可见性 有趣的是,通常lint会报告您无法编写此方法,因为它会隐藏基类方法,但在这种特殊情况下(注意缺少@Override指令),此方法会被调用,就好像它是在基类中编写的一样。所有调用此方法的方法都将调用覆盖,而不是原始方法。对于我

我一直在玩Android中的SVG支持,并提出了一个库,声称它支持SVG,就像它是本地的一样

因为我费了很大的劲才发现这是不可能的,所以我去看看这个家伙是怎么做到的。所以我找到了他的方法,他在其中声明了一个方法(
loadDrawable
),该方法在基本资源类中具有默认可见性

有趣的是,通常lint会报告您无法编写此方法,因为它会隐藏基类方法,但在这种特殊情况下(注意缺少
@Override
指令),此方法会被调用,就好像它是在基类中编写的一样。所有调用此方法的方法都将调用覆盖,而不是原始方法。对于我来说,这完全是无法理解的,因为我来自经典的编译器,如
C++
Pascal

基于此,我通过一次使用反射就成功地获得了SVG支持,对此我非常高兴,但是:


为什么这样做?

看起来Dalvik解释器中存在允许重写包私有方法的错误。显然,Google已经意识到了这个问题(在Jelly Bean中?),因为Dalvik报告了一个警告,在这种情况下它错误地重写了包私有方法,而ART报告它是一个错误,并且无法编译它。正确的行为当然是允许它,但不允许覆盖来自其他包的包私有方法,但谷歌似乎希望避免破坏依赖于此行为的现有应用程序

更新:这已在6月16日的ART文档更新中正式发布,尽管它声明ART发出警告,而不是velis在对问题的评论中指出的严重错误:

Dalvik错误地允许子类重写包私有方法。ART在这种情况下发出警告:

在Android 4.1之前,方法void com.foo.Bar.qux()
将错误地覆盖
com.qux.qux

如果要重写其他包中的类方法,请将该方法声明为
public
protected


是的,我在设计一个扩展其中一个默认小部件的自定义小部件时也遇到了这个问题,我复制了一个包私有回调方法,考虑手动实现它的语义。我惊讶地注意到,这导致框架实现被覆盖,而不可能调用它。当时我没有太多时间调查这个问题,所以我只是将方法签名改为private。现在,在不同的Android API级别和Oracle JVM上进行测试后,这似乎是Dalvik实现中的一个bug。您确定该方法覆盖了基类的方法吗?在包外部的子类中重用私有或包私有方法名是合法的。如果不是这样的话,这个事实会泄露类的实现信息。但它不应该被称为好像它覆盖了原来的。我是。有一个名为
getDrawable
的方法,它调用
loadDrawable
,我还没有覆盖它,即使继承的
getDrawable
调用它,我的
loadDrawable
仍然被调用。最初我只是认为我必须将两者都替换,这样对
loadDrawable
的任何外部调用都会被我的
loadDrawable
捕获,而任何
getDrawable
都会被我的覆盖捕获,但事实证明这根本没有必要。@flup:您可以通过为此编写一个简单的测试用例来轻松测试,并在Android和另一个JVM上运行它。您将看到,它将在其他JVM上按预期工作,正如在Android中所述。@corsair992:您实际上已经测试并确认了这一点?我应该在这里注意到,只有当应用程序尝试此操作时,其行为才会改变,不再崩溃,但它也无法工作。