java构造方法不允许调用重载方法
今年在搭建一个项目的基础架构的时候,遇到了一个问题,一个类的初始化对象总是得到错误的数据,从常规语法上不到赋值错误。java代码大概如下:
import org.junit.Test;
public class ConstructorInvokeOverrideTest {
@Test
public void test() {
new FlowView(1234);
}
class FlowView extends BaseView {
int layoutId;
public FlowView(/*Context context, */ int layoutId) {
super(/*context*/);
this.layoutId = layoutId;
}
@Override
protected int getLayoutId() {
return layoutId;
}
}
abstract class BaseView {
BaseView(/*Context context*/) {
inflate(getLayoutId());
}
public void inflate(int layoutId) {
System.out.println("layoutId: " + layoutId);
}
protected abstract int getLayoutId();
}
}
输出结果
layoutId: 0
按照设计思路,此处应该是打印layoutId:1234。可是事与愿违,打印的是layoutId。因为实际代码行数很多,当时模块比较多,一直以为是其他模块的初始化导致的,然后叫坐在身边的同事一起review代码,对方也没看出个所以然(这里告诉大家一个查bug的技巧,在实战中,交叉review是非常高效的解决问题方法,可以排除一些常规的低级错误,与开发人员双方水平无关)
范例说明:
1. 在实际代码中,一直是抛出异常;
2. 为了避嫌避免泄漏商业代码,构造函数并非是layoutId,重载的函数也不是getLayoutId();
3. Context是在Android中的一个上下文句柄,此处代码为了简洁,我们忽略掉该初始化参数,加上注释的原因是为了让读者更好理解实际继承时是有初始化参数的。
问题原因:
对于这个问题,只能推翻重来,把本次修改的内容一点点回退。最终发现原来犯了一个语法错误。
1. FlowView中定义了成员变量layoutId;
2. BaseView的getLayoutId是一个可以重载的方法;
3. FlowView继承并覆盖了getLayoutId并且BaseView的构造函数中调用了getLayoutId;
那么就导致一个问题,父类在构造函数调用继承重载方法时,子类并没有完成实例化(因为父类和子类的构造函数还没有执行完),子类FlowView成员变量layoutId可能还没有完成初始化。
发现这个问题后,一百度,果然很多人犯过在构造方法中调用重载方法的错误。修改这个问题也很简单,在构造函数中不调用重载方法。
另外,BaseView的getLayoutId是一个抽象方法。即使不用抽象方法,结果还是一样。
public class ConstructorInvokeOverrideTest {
@Test
public void test() {
new FlowView(1234);
}
class FlowView extends BaseView {
int layoutId;
public FlowView(/*Context context, */ int layoutId) {
super(/*context*/);
this.layoutId = layoutId;
}
@Override
protected int getLayoutId() {
return layoutId;
}
}
// no abstract class.
class BaseView {
BaseView(/*Context context*/) {
inflate(getLayoutId());
}
public void inflate(int layoutId) {
System.out.println("layoutId: " + layoutId);
}
protected int getLayoutId() {
return -1;
}
}
}
输出结果:
layoutId: 0
注意:是0,而不是-1。 因为getLayoutId()已经被重载覆盖了。
最后,输出结果可能在Oracle JDK18和Android上面的结果可能不一样。
本博客的运行环境是:
java version "1.8.0_152"
Java(TM) SE Runtime Environment (build 1.8.0_152-b16)
Java HotSpot(TM) 64-Bit Server VM (build 25.152-b16, mixed mode)