[JAVA]重写父类方法并向上转型时的初始化问题
来源:互联网 发布:js定时器重复执行 编辑:程序博客网 时间:2024/06/05 18:10
其实是个小问题,不过蛮有意思的。
这个问题的提出,是今天朋友问我的一个问题。我来大概描述一下这个问题:
如何模仿安卓的Activity,设计一个父类,使得对象被创建(调用)时某些周期函数依次被调用,且该性质不因子类的重写而被破坏。举个例子:
open class sup(){ //假设父类已实现A -> B -> C 的周期执行顺序 open fun A(){ println("f A") } open fun B(){ println("f B") } open fun c(){ println("f C") }}class sub:sup(){ override fun A() { super.A() println("这行执行完再执行B()") } override fun B() { println("c B") }}
应当预计输出:
f A这行执行完再执行B()c Bf C
其实这就是安卓Activity的几个生命周期,都很熟悉了:
我说很简单啊,在父类的构造或初始化函数中写个顺序就好了:
init { println("父类构造") A() B() C()}
经过测试,这样写是没问题的,输出符合上面的预期。
然后他问了一句话,困扰了我不少时间(现在想来应该还是我对继承和重写的理解没有到位导致的问题):
他说,就算是向上转型,但这时候父类初始函数中写的A、B、C,为什么会是被重写过的子类中的A、B、C方法,子类不是还没构造么?如果子类A方法中要输出子类私有变量var1的值,但此时子类还没构造(假设子类var1在子类构造函数中赋值),岂不是直接就空了?
我们都知道,构造时的执行顺序是:父类静态 -> 子类静态 -> 父类一般语句 -> 父类构造 -> 子类一般语句 -> 子类构造。
他说的这个问题,好像有点道理啊...
可能文字说明比较不好理解,那我们转换成代码,结合红字标示的顺序来看一下这个问题:
public class Test { public static void main(String[] arg){ sup1 s1 = new sub1();//会输出什么呢? }}class sup1{ public sup1(){ System.out.println("父类"); A(); B(); C(); } public void A(){ System.out.println("f A"); } public void B(){ System.out.println("f B"); } public void C(){ System.out.println("f C"); }}class sub1 extends sup1{ public int var1 = 8; public sub1(){ System.out.println("子类"); var1 = 7 ; } public void A(){ super.A(); System.out.println(var1); }}
所以我就开始想,难不成父类中构造方法,执行的是父类中的ABC,因为这样可以避免被子类重写后,抛出Null异常。毕竟上层如果不对下层开放,这么去处理,真的是个非常大的隐患:下层根本查不出来(先不考虑这么设计父类合理不合理)于是我想,Java应该会有避免机制的吧.....应该有的吧....
----------------
然而,上面这段代码最后输出:父类f A0 // 不是8 也不是7 ; 同时也说明了执行了子类中重写的方法。0是默认赋值,但如果var1是个对象,这里就真的是空的。f Bf C子类执行顺序没问题,但是值var1确实空了。居然真的空了Orz......害怕.jpg
感觉不想点别的方法, 这会是个隐蔽性很高的雷...我拿据称Null控制机制做得很好的Kotlin去试了一下,在非"?"的情况下编译通过,但是也是抛空。也就是说,这是一个现有机制检测不出的Null隐患...
先马克一下,硬脆思婷。
PS:
我去看了安卓的源码,大概知道了他的处理方式。简单说一下,他不是放在构造函数里完成对象创建时自动按周期函数执行,而是通过一个ActivityMannager来处理。ActivityMannager管理一个任务栈,任务栈调用栈中某个Activity中的非构造函数callOnxxx()。这个函数类似于上面的init{},不太一样,但是本质上是一样的。
大概就像这样:
class MyActivity{ public void onCreate(){ System.out.println("F onCreate"); } public void onStart(){ System.out.println("F onStart"); } public void onResume(){ System.out.println("F onResume"); } public void onPause(){ System.out.println("F onPause"); } public void onStop(){ System.out.println("F onStop"); } public void onDestory(){ System.out.println("F onDestory"); } public void onRestart(){ System.out.println("F onRestart"); } //任务栈调用唤醒周期函数callOnXX() public final void callOnCreate(){ onCreate(); callOnStart(); } public final void callOnStart(){ onStart(); onResume(); } public final void callOnPause(){ onPause(); onStop(); } public final void callOnRestart(){ onRestart(); callOnStart(); } public final void callOnResume(){ onResume(); }}//测试类class TestActivity extends MyActivity{ @Override public void onStart() { super.onStart(); System.out.println("C onStart"); }}
- [JAVA]重写父类方法并向上转型时的初始化问题
- java向上转型方法调用的问题
- java向上转型过程中方法重写
- java多态中向上转型+重写的奥秘
- java中的类的向上转型向下转型问题
- java类的向上转型
- 向上转型之后的方法调用问题
- Java的向上转型
- 求证:Java向上转型,转型后得到的对象具有导出类(实现类)的方法
- java笔记(三)[java中的继承&java中的方法重载,重写,重构&java中的向上转型和乡下转型&java中的抽象类和接口&java中的接口向上转型]
- java自动向上转型问题
- Java向上向下转型问题
- java 向上转型之后调用子类的同名变量/方法的问题(多态)
- (多态)Java向上转型之后调用子类的同名变量/方法的问题
- (java)对象引用向上转型后,无法调用子类独有的方法和属性问题
- 向上转型和向下转型的问题
- Java向上转型与向下转型(子类的对象赋给父类的)
- JAVA的向上转型及向下转型
- JAVA获取100以内所有的奇数
- poj 2262 Goldbach's Conjecture 【素数筛法】
- 深度解析Mybatis缓存
- pgpool+流复制恢复备机的方法
- 你是码农还是优秀的程序员?
- [JAVA]重写父类方法并向上转型时的初始化问题
- Maximum_Subarray
- 关于IP选项
- python
- 设计模式学习之生成器模式与实例
- 176. Second Highest Salary
- LintCode 67.二叉树的中序遍历
- mybatis一对多关系 collection的使用
- 东方财富研发岗位笔试题