困惑的Android访问控制机制。它与java不同

时间:2012-12-14 04:04:39

标签: java android access-control

在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()并且永远不会通知我们的监听器。这是由于重写造成的。我错了吗?

1 个答案:

答案 0 :(得分:1)

Android和Java中的访问控制完全相同。

Spinner中没有onSelectionChanged()方法 - 至少不是publicprotected。如果有像这样的package-private方法,你可以覆盖它,但前提是你的类在同一个包中,而不是。您已经简单地声明了一个具有相同名称的无关方法;它没有压倒一切。

这就是为什么你应该在你想要覆盖方法的地方使用@Override。它会产生一个编译错误,告诉你实际上没有覆盖。