当我从抽象超类活动的子类中调用一个方法时发生了什么?

时间:2015-04-13 20:19:04

标签: java android inheritance casting

我想从我的超类(扩展活动)中调用子类函数。但是,我无法找到子类的实例,所以我只是天真地尝试向下转换我的抽象超类并调用它的方法来看看会发生什么。我没想到这会起作用 - 超类如何知道调用该方法的实例?

public abstract class RootActivity extends Activity{
    private flag someCondition;

    @Override 
    protected void onCreate(Bundle savedInstanceState){ 
        //... 
    }
    // ... 

    public void startJob(JobAction.Id jobaction){
        Log.d("Zlatan", "started a job");
        if (!jobaction.someCondition){
            return;
        }else{
            ((SpecificJob) this).dontDelete(); //<--- What have I done?
            startSomeLongAsynchronousJob(someCondition);
            Log.d("Zlatan", "calling finish");
            finish();
        }

    }
    // ...
    public void someOtherFunction(){
        finish();
    }
    @Override 
    public boolean onKeyDown(int keyCode, KeyEvent event){
        //...
        startJob(JobAction.SOMEENUM);  //Startjob is being called in the superclass
    }
}
}

我这里有一个子类。该活动是由另一项活动启动的,我也在此处包含了清单代码段。

public class SpecificJob extends SomeClassThatExtendsRootActivity{
    //SomeClassThatExtendsRootActivity extends RootActivity - I've ommitted it
    private boolean flag = false;
    @Override
    public void onCreate(Bundle bundle){
        super.onCreate(bundle);
        //...
    }
    // ... some code ...
    public void dontDelete(){ //Not static
        flag = true;
        Log.d("Zlatan", "I set flag"); //This doesn't appear in log
    }

    @Override 
    public void onDestroy(){
        Log.d("Zlatan", "When finishing, flag is now " + flag);
    }
}

<activity
        android:name=".SpecificJob"
        android:label="@string/TXT_BOOKMARKS"
        android:icon="@drawable/ic_launcher"
        android:theme="@style/stuff"
        android:launchMode="singleTask"
        android:windowSoftInputMode="stateHidden"
        android:taskAffinity=".SpecificJob">
        <intent-filter>
            <action android:name="com.me.feature.SOME_WORKFLOW" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
        <meta-data
            android:name="concurrency"
            android:value="DEFAULT_CONCURRENCES|printer"
            />
    </activity>

令我惊讶的是,没有错误或崩溃。我的结果是

D/Zlatan started a job
D/Zlatan calling finish
D/Zlatan﹕ When finishing, flag is now false

我没有看到我在SpecificJob.dontDelete()中写的日志。我的问题是

1)这在运行时做了什么?为什么我没有看到&#34;我设置了旗帜&#34;,为什么它没有崩溃?

2)如何从RootActivity中最好地调用SpecificJob中的函数?

2 个答案:

答案 0 :(得分:1)

直到运行时才取消选中强制转换,并且当您从RootActivity继承SpecificJob并且仅在SpecificJob上调用startJob()时,生成的对象仍然是SpecificJob类型。这意味着可以毫无问题地进行演员表演。如果您要扩展RootActivity并尝试在这个新类上调用startJob(),它将无法工作。

你不应该从超类中调用子类。超类不应该知道如何扩展它。可能有更好的方法,你怎么想这样做?

更新:所以将RootActivity将使用的所有清理代码以及在RootActivity的onDestroy方法中继承它的任何类放入。

public abstract class RootActivity extends Activity{
    @Override 
    public void onDestroy(){
        // All cleanup code common to inherited classes goes here
    }
}

然后在SpecificJob中调用super.onDestroy,然后调用SpecificJob独有的任何代码。

public class SpecificJob extends SomeClassThatExtendsRootActivity{
    @Override 
    public void onDestroy(){
        super.onDestroy();
        // All cleanup code unique to this class goes here
    }    

}

答案 1 :(得分:1)

就像已经提到的那样,这是有效的,因为对象&#34;知道&#34;它们的类型和类型转换仅在运行时检查。因此,如果在startJob()实例上调用SpecificJob,它将起作用。但是如果在另一个RootActivity子类的实例上调用该方法,则会在运行时获得异常。这也是你应该尽可能避免使用类型转换的原因。

在这种特殊情况下,以类型安全的方式编写代码很容易。只需将方法dontDelete()的声明添加到RootActivity,就像这样

protected abstract void dontDelete();

这会强制具体的子类实现该方法,并且不需要使用类型转换。