我是初学者,目前正在阅读继承和多态。我对关键字"扩展"有一些困惑。以及如何调用构造函数。这是代码:
public class Test {
public static void main(String[] args) {
new B();
}
}
class A {
int i = 7;
public A() {
System.out.println("i from A is " + i);
}
public void setI(int i) {
this.i = 2 * i;
}
}
class B extends A {
public B() {
setI(20);
System.out.println("i from B is " + i);
}
public void setI(int i) {
this.i = 3 * i;
}
}
我知道通过在第3行调用B(),调用了A类的构造函数,然后调用了B(是吗?)因此它显示了" i来自A是7"然后"我来自B是60"。但有人可以解释这个的重要性吗?为什么B中的int i与A中的i完全不同?再一次,我在跟踪"路径"时遇到了麻烦。新行B()之后的代码。如果有人可以在调用B()之后解释每一步,那将非常感激。
答案 0 :(得分:10)
我遇到新行后跟踪代码“路径”的问题 B()。如果有人可以在调用B()后解释每一步,那就是 我将不胜感激。
调用new B()
时,流技术上首先进入构造函数B()
。 Java中的构造函数总是需要(最终)链接到更高的构造函数(递归到达最高类Object
)。链接由super(...)
或this(...)
语句表示为构造函数的第一个语句。如果没有明确写入,则假定无参数super()
。所以,B()
实际编译就好像它是这样写的:
public B() {
super();
setI(20);
System.out.println("i from B is " + i);
}
现在,您可以清楚地看到new B()
来电B()
来调用A()
(调用println
并退出),然后setI
,最后{{1} }}
为什么B中的int i与A中的i完全不同?
println
是完全相同的字段。不同之处在于您在两个打印输出之间调用i
,从而更改了setI(20)
的值。如果您移除了对i
的通话,则会看到该值仍为setI
。
答案 1 :(得分:1)
当您创建B实例并调用构造函数B()时,它将首先调用super()
,在您的情况下将调用A()
。
这会打印i from A is 7
,因为默认情况下您将i
设置为。{/ p>
在调用super之后,它会移动到下一行,即setI(20)
。此行将B中的i
设置为60,因为您的setI(int i)
方法将参数(20)乘以3,然后将i
设置为该值。
然后,您正在打印i from B is 60
因为i
现在是60。
答案 2 :(得分:1)
Java语言规范说
如果构造函数体不是以显式构造函数调用开始并且声明的构造函数不是原始类Object的一部分,那么构造函数体隐式地以超类构造函数调用“super();”开头,调用它的直接超类的构造函数,不带参数。
这意味着当您编写new B()
时,B
的构造函数所做的第一件事就是调用A
的构造函数。在A
的构造函数将i
设置为7后,B
的构造函数会调用setI(20)
,这会将i
的值更改为60.只有一个i
- 在A
和B
中没有区别。它只是在println
和下一个{{1}}之间改变了价值。
答案 3 :(得分:0)
子类必须始终通过super()调用其超类的构造函数,或者使用super和该构造函数的参数调用另一个构造函数。
如果你没有明确地添加super(),Java将在幕后为你做。
class B extends A {
}
与呼叫相同:
class B extends A {
public B() {
super();
}
}
知道这一点,显然调用new B();
将调用B构造函数,然后在完成之前调用A构造函数。
答案 4 :(得分:0)
当你呼叫new B()
时,VM调用implicity super(),然后一个新的A()正在写7,但在你的setI中你覆盖了这个方法,这是因为你看到了60。
使用anotation @Override总是一个好主意。
BR