我正在学习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名称首先在makeName()
类的Point
方法中初始化,然后应该变得不可变?我错了吗?
答案 0 :(得分:2)
在设置makeName()
;
this.color = color
方法
当颜色变量仍为makeName()
时,super.construtctor会调用null
方法。
答案 1 :(得分:0)
super(x,y)是ColorPoint类的调用方法makeName(),直到那时才分配颜色。
答案 2 :(得分:0)
Flow就是这样,
Point constructor > makeName of ColorPoint > makeName of Point
因为,首先调用ColorPoint的makeName,直到那时没有赋值color属性值,所以它给出null
答案 3 :(得分:0)
makeName()
。
当它被调用时,颜色尚未设置,因此颜色的默认值为空。
要解决此问题,您必须在构造函数的末尾显式调用makeName()
。这是正确的代码:
public ColorPoint(int x,int y, String color){
super(x,y);
this.color = color;
makeName();
}
答案 4 :(得分:0)
new ColorPoint(4,2,"viola"));
在第22行调用构造函数,该行调用第5行的构造函数 第5行的构造函数在第27行调用重写的函数make name 将名称设置为[4,2]:null,因为颜色尚未初始化。
答案 5 :(得分:0)
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
因此,当您看到final变量具有其默认值时,可以稍后在构造函数中修改一次。
但是让我们回到你的例子。当你打电话
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
之前所看到的那样,您正在调用super(x,y)
,代码如下所示:
public Point(int x, int y) {
this.x = x;
this.y = y;
name = makeName();
}
但是makeName();
感谢多态(late binding),你使用makeName
类的ColorPoint
代码,看起来像
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
。
由于ColorPoint
从toString
继承Point
,看起来像
public final String toString() {
return name;
}
您将name
中存储的输出值视为[4 ,2]:null
。