【发布时间】:2026-01-17 21:25:01
【问题描述】:
在java中,如果不在同一个包中,子类不能覆盖基类的默认或私有方法。 基类代码:
//base class
public class TestBase {
protected void test() {
defaultTest();
protectedTest();
privateTest();
}
void defaultTest() {
System.out.println("defaultTest");
}
protected void protectedTest() {
System.out.println("protectedTest");
}
private void privateTest() {
System.out.println("privateTest");
}
}
和子类代码:
public class TestImpl extends TestBase {
protected void test() {
super.test();
localTest();
}
private void localTest() {
System.out.println("Impl:localTest");
}
protected void defaultTest() {
System.out.println("Impl:defaultTest");
}
protected void protectedTest() {
System.out.println("Impl:protectedTest");
}
public void privateTest() {
System.out.println("Impl:privateTest");
}
public static void main(String[] args) {
new TestImpl().test();
}
}
让我们将它们放入不同的包中,输出为:
defaultTest
Impl:protectedTest
privateTest
Impl:localTest
这反映了java中的访问控制机制。我们不能覆盖子类中的 defaultTest() 方法。但是在andorid中,我们可以! 在android.widget.AdapterView类中,有一个默认方法:
void checkSelectionChanged() {
if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) {
selectionChanged();
mOldSelectedPosition = mSelectedPosition;
mOldSelectedRowId = mSelectedRowId;
}
}
因此,同一包中的任何子类,例如 Spinner,都可以调用 checkSelectionChanged() 方法。然后调用 OnItemSelectedListener。我们可以添加自己的监听器来监听事件,我们会收到更改通知。 但是,如果我们扩展 Spinner,比如 CustomSpinner,并在 CustomSpinner 中定义相同的方法,代码如下:
public class CustomSpinner extends Spinner{
public CustomSpinner(Context context, AttributeSet attrs, int defStyle,
int mode) {
super(context, attrs, defStyle, mode);
}
public CustomSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomSpinner(Context context, int mode) {
super(context, mode);
}
public CustomSpinner(Context context) {
super(context);
}
void checkSelectionChanged() {
Log.i("CustomSpinner", "Called!");
}
}
然后奇怪的是 CustomSpinner 中的 checkSelectionChanged() 被调用并且我们的监听器永远不会被通知。这是由覆盖引起的。我错了吗?
【问题讨论】:
-
我没有将其发布为答案,因为我不确定,但我认为重写方法意味着超类和子类方法的访问修饰符必须相同。在您的示例中并非如此。
-
事实上,无论子类中定义哪个修饰符,我得到的结果都是一样的。
-
@gsingh2011 相同或更宽的访问修饰符...
-
它根本不可能。 Google 只制作了自定义 JVM,而不是自定义语言规范。我不清楚为什么你认为 android 会执行不同的访问规则,但你能解释一下你认为在 android 中会发生什么和你的测试类吗?
-
@Thihara 我只是用我的 CustomSpinner 替换 android.widget.Spinner。我的方法 checkSelectionChanged() 在没有任何我的代码调用的情况下被调用。 Android Spinner 通过在内部调用 checkSelectionChanged() 来唤醒任何已注册的 OnItemSelectedListener。我认为不应该调用我的 checkSelectionChanged() 来影响 android 中的内部逻辑,因为在 java 中,我的 checkSelectionChanged() 不应该是覆盖代码,并且在我的 CustomSpinner 中只是本地的,正如 java 测试类所示
标签: java android access-control