繁体   English   中英

Java:输出意外结果

[英]Java: got an unexpected output

我正在学习Java,却得到了意外的输出。 那是代码:

public class Point {
    protected final int x,y;
    private final String name;

    public Point(int x,int y){
        this.x = x;
        this.y = y;
        name = makeName();
    }

    protected String makeName() {

        return "["+x+" ,"+y+"]";
    }
    public final String toString(){
        return name;
    }
}
public class ColorPoint extends Point{
    private final String color;

    public ColorPoint(int x,int y, String color){
        super(x,y);
        this.color = color;
    }

    protected String makeName(){
        return super.makeName() + ":" + color;
    }

    public static void main (String[] args){
        System.out.println(
                new ColorPoint(4,2,"viola"));
    }
}

输出为: [4,2]:null
为什么? 不应该只是[4,2]因为变量String名称首先在Point类的makeName()方法中初始化,然后应该变为不可变的吗? 我错了吗?

在设置this.color = color之前,将调用makeName()方法。

当color变量仍然为null时,super.construtctor将调用makeName()方法。

super(x,y)调用ColorPoint类的makeName()方法,直到那时才分配颜色。

流是这样的,

Point constructor > makeName of ColorPoint > makeName of Point

由于ColorPoint的makeName首先被调用,直到那个时候没有分配颜色属性值,所以它给出null

在超类的构造函数中调用makeName() 调用时尚未设置颜色,因此color的默认值为null。

要解决该问题,您必须在构造函数的末尾显式调用makeName() 这是正确的代码:

public ColorPoint(int x,int y, String color){
    super(x,y);
    this.color = color;
    makeName();
}
 new ColorPoint(4,2,"viola"));

在第22行调用构造函数,然后在第5行调用构造函数,在第5行调用构造函数在第27行调用覆盖的函数make name,该函数将name设置为[4,2]:null,因为尚未初始化颜色。

final字段使用默认值(对于引用为null )初始化。 您可以使用以下代码轻松检查它:

class FinalTest{
    public final String value = test();

    private String test() {
        System.out.println("current state of value is '"+value+"'");
        return "foo";
    }

    public static void main(String[] args) {
        FinalTest ft = new FinalTest();
        System.out.println(ft.value);
    }
}

产生输出:

current state of value is 'null'
foo

因此,如您所见,最终变量具有其默认值,以后可以在构造函数中对其进行一次修改。

但是,让我们回到您的示例。 你打电话时

System.out.println(new ColorPoint(4, 2, "viola"));

您正在创建ColorPoint类的调用构造函数,然后在此实例上将调用toString 但是,让我们仔细看看ColorPoint构造函数:

public ColorPoint(int x, int y, String color) {
    super(x, y);
    this.color = color;
}

正如您在this.color之前看到的this.color您正在调用super(x,y) ,其代码如下所示:

public Point(int x, int y) {
    this.x = x;
    this.y = y;
    name = makeName();
}

但是在makeName(); 由于多态性( 后期绑定 ),你正在使用的代码makeNameColorPoint类,它看起来像

protected String makeName() {
    return super.makeName() + ":" + color;
}

因此,在开始时,您将获得super.makeName()结果,其结果为"[" + x + " ," + y + "]"但随后您尝试访问的color (如您所记未初始化)

super(x, y); //<-- we are still here
this.color = color;//this wasn't invoked (yet)

因此color仍具有其默认值( null )。

这意味着name将设置为[4 ,2]:null

由于ColorPointPoint继承toString ,看起来像

public final String toString() {
    return name;
}

您会看到以[4 ,2]:null name存储的输出值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM