public class TestA1{
public TestA1(){ // 4
System.out.println("P "); // 5 打印出P
this.init(); // 6,这里的this应该指的是TestB1 d,所以调用TestB1
} //的方法init()
void init(){
System.out.println("Q ");
}
public static void main(String argv[]){
TestB1 d= new TestB1();//程序从这里开始,1
}
}
class TestB1 extends TestA1{
int i =1;
public TestB1(){ // 2
super(); // 3,调用基类的构造方法
System.out.println(i); // 10 打印出 1
}
void init(){ // 7
System.out.println("C "); // 8 打印出C
i = 2;
System.out.println(i +" "); //9 打印出 2
}
}
public TestA1(){ // 4
System.out.println("P "); // 5 打印出P
this.init(); // 6,这里的this应该指的是TestB1 d,所以调用TestB1
} //的方法init()
void init(){
System.out.println("Q ");
}
public static void main(String argv[]){
TestB1 d= new TestB1();//程序从这里开始,1
}
}
class TestB1 extends TestA1{
int i =1;
public TestB1(){ // 2
super(); // 3,调用基类的构造方法
System.out.println(i); // 10 打印出 1
}
void init(){ // 7
System.out.println("C "); // 8 打印出C
i = 2;
System.out.println(i +" "); //9 打印出 2
}
}
解决方案 »
- java调用bat怎么没有反应????
- 在属性定义的地方初始化和在构造方法里初始化有和区别?
- 为什么运行后就提示这样的错误:Exception in thread "main" java.lang.Error: Unresolved compilation problem:
- 对象调用方法后会怎么样?是否可以嵌套调用方法
- 遇到这样一个奇怪的问题
- 怎么在contentPane 中切换显示几个jpanel
- 悬赏百分解决httpunit处理下拉框的问题(问题解决立即结贴)
- 创建网站的 RSS 内容摘要
- 在JBUILDER7中作JAR文件
- 如何实现数据库的事务管理(新手的SOS!!)
- SOS~~~~
- 如何把一个浮点数分整数和小数显示?
我认为是TestB1中的
init()重载了TestA1中
init()
首先,TestB1继承TestA1,因此TestB1的void init()函数覆盖TestA1的void init()函数
其次,在主函数中TestB1 d= new TestB1();调用TestB1的构造函数,TestB1(),在TestB1中super()使得,TestB1调用他的父类TestA1的构造函数,TestA1(),因此
首先执行System.out.println("P ");输出P
再执行this.init();因此执行TestA1的init(),但是TestA1的init()已经被TestB1的init()重写,因此执行System.out.println("C ");
i = 2;
System.out.println(i +" ");
输出
C
2
最后再回到
public TestB1(){
super();
System.out.println(i);
}
中,执行System.out.println(i);输出1 //此时i的值仍为1
为什么第四行“这里的this应该指的是TestB1 d,所以调用TestB1”
1、构造器的调用顺序,构造器是按派生顺序从基类到子类的,
2、方法覆盖中,当将子类句柄变量传递给基类对象时,所引用的句柄对象的类型决定执行哪个版本的函数。
所在这个程序中;
1、当创建一个TestB1对象时,首先调用TestA1的构造器,所以执行System.out.println("P "); 输出P 。
2、然后执行TestA1的构造器中的this.init(),于是产生方法覆盖问题,由于引用的是TestB1对象,所以执行TestB1的init()函数,输出输出C和2。
3、最后执行TestB1的构造器而执行System.out.println(i),输出1。
4、在执行TestA1的构造器中this.init()时,还有一个造型问题,也就是将TestB1转化为TestA1,但实际上这时this是引用(或者指向)一个TestB1的句柄变量,所以执行TestB1的init()函数。
在构造函数中,要做尽量简单的动作,以避免你的程序存在漏洞。
就上面的例子,当别人从你的类中继承来,他就可以让你的类执行到自己设计的代码,而不是你所愿意的。
如果在构造函数中调用的是private的方法,那就不会有这些情况出现了。
建议看看<thinking in Java 2/ed>与此相关的内容.
this是对当前对象引用的一个句柄变量(是不是可以认为是一个常量呢),这里只构造了TestB1的一个对象,所以this.init()应该是指TestB1的方法。
至于去掉this之后仍然输出原结果,我想应该是方法重载的效果。
我对下面程序用debug作了一下追踪调试,附有执行顺序。
public class TestA1{
public TestA1(){//3
System.out.println("P ");//4
this.init();//5
}//10
void init(){
System.out.println("Q ");
}
public static void main(String argv[]){
TestB1 d= new TestB1();//1.......14
}//15
}
class TestB1 extends TestA1{
int i=10;//11
public TestB1(){//2
//super();
System.out.println(i);//12
}//13
void init(){
System.out.println("C ");//6
i++;//7
System.out.println(i +" ");//8
}//9
}
执行结果为
Q C 1 10
我想问,既然i++在 int i=10之前执行,为什么没有出现i未被初始化的错误。
由结果,我们也可以看出,在i++之前i是有值的为0,那么i是在什么时候被设定为整形且赋予初始值0的呢?关键是为什么!
执行程序时候,
遇到TestB1 d = new TestB1();
构建器申请内存把class TestB1 加载进来,并把内存区域擦干净,这是i(及其有关的成员变量)就是默认值0。
接着,因为 'extends TestA1', 所以不再进行动作,先加载 TestA1,也一样TestA1此时设置默认值。为什么不先 初始化i = 10, 是考虑到可能这个初始化动作会受到父类初始化值的影响,所以要在父类初始化后再初始化子类的成员变量。
String s = "T1";
protected T1(String s) {
this.s = s + this.s; //this
this.msg(); //:如果这个this与上一行的this没什么不同,那么this就不是指向TestB1
}
void msg() { System.out.println(s); }
T1 getT1() { return this; }
}
class T2 extends T1 {
String s = super.s + "'s son";
T2(String s) {
super(s);
this.msg();
}
void msg() { System.out.println(s); }
T2 getT2() { return this; }
}
public class Test02 {
public static void main(String[] args) {
T2 t = new T2("hi ");
}
}
输出:
null
hi T1's son似乎常见的this的作用就两个,如上例子,一是用来和方法那变量区分,一是 return this。
class T1 {
String s = "T1";
protected T1(String s) {
this.s = s + this.s;
this.msg(); // call overrided msg(), print 'null'
this.msg("");// call native msg(""), print 'hi T1'
}
void msg() { System.out.println(s); }
private void msg(String trash) { System.out.println(s); }
}
class T2 extends T1 {
String s = super.s + "'s son";
T2(String s) {
super(s);
this.msg(); //print "hi T1's son"
this.msg(""); //print "hi T1's son"
}
void msg() { System.out.println(s); }
void msg(String trash) { System.out.println(s); }
}
public class Test02 {
public static void main(String[] args) {
T2 t = new T2("hi ");
}
}
结果:
null
hi T1
hi T1's son
hi T1's son
你这两段程序确实很好,他不仅说明了this的用法也说明了初始化顺序的问题。
在think in java中是这样说明初始化顺序的:
(1) 在采取其他任何操作之前,为对象分配的存储空间初始化成二进制零(或null)。
(2) 调用基础类构建器。此时,被覆盖的msg()方法会得到调用(的确是在T2构建器调用之前),此时会发现s的值为null,这是由于步骤(1)造成的。
(3) 按照原先声明的顺序调用成员初始化代码。
(4) 调用衍生类构建器的主体。
下面我再将你的第一个源程序运行顺序标示出来,互相比较,就可以看出其中的奥妙。
class T1 {
String s = "T1"; //4
protected T1(String s) { //3
this.s = s + this.s; //5
this.msg(); //6
} //8
void msg() { System.out.println(s); }
T1 getT1() { return this; }
}
class T2 extends T1 {
String s = super.s + "'s son"; //9
T2(String s) {
super(s); //2
this.msg(); //10
} //12
void msg() { System.out.println(s); } //7.....//11
T2 getT2() { return this; }
}
public class Test02 {
public static void main(String[] args) {
T2 t = new T2("hi "); //1......//13
} //14
}
至于this的含义,就只有一个指向当前类,
this.s、this.msg();和return this;是三种用法,但是他们的含义是相同的,都是指向当前类。而对于this.msg();和this.s中的this完全可以不要。
1 java 中所有的成员方法都是 “虚函数”, 对象只调用真实对象中的对应方法。在本例子中super构造器调用的init方法实际上是调用TestB1的init方法。
2 构造器中的执行顺序
调用super构造器
初始化成员变量
执行构造器的其他部分
关于:“java 中所有的成员方法都是 “虚函数””这种说法有没有详细的说明,我想看看,或者在《think in java》 中有没有,因为我只有这本书,
关于:“java 中所有的成员方法都是 “虚函数””这种说法有没有详细的说明,我想看看,或者在《think in java》 中有没有,因为我只有这本书,
似乎java并没有要向程序员介绍"虚函数"概念的意思的。
"虚函数"只是熟悉C++的同行在比较Java&C++时候的一种归纳挂。
所以,你想详细"虚函数",可能需要看<thinking in c++>啦。呵呵和
以下是sl-275中的部分内容
Polymorphism
• Polymorphism is the ability to have many different
forms; for example, the Manager class has access to
methods from Employee class.
• An object has only one form.
• A reference variable can refer to objects of different
forms.Polymorphism
Employee employee = new Manager(); // legal
// Illegal attempt to assign Manager attribute
employee. department = "Sales";
// the variable is declared as an Employee type,
// even though the Manager object has that attributeVirtual Method Invocation
• Virtual method invocation:
Employee e = new Manager();
e. getDetails();
• Compile- time type and runtime type
static int j=5;
int i=5;
}我用SUN J2SE1。3的编译器做了一个试验,发现:
(instance变量)i=5;是被编译进了构造器,放在构造器的开始部分.
(static变量)j=5;是被编译进了一个“静态初始化块”另外,通过以前的帖子你会发现,静态函数和private函数不是“虚函数”,是“编译期绑定的”。