当前位置:  技术问答>java相关

轻松解答,高分相送!

    来源: 互联网  发布时间:2015-03-23

    本文导语:  public class TestA1{  public TestA1(){   System.out.println("P ");   this.init();  }  void init(){   System.out.println("Q ");  }  public static void main(String argv[]){   TestB1 d=  new TestB1();  } } class TestB1 extends TestA1{  int i =1;  public...

public class TestA1{
 public TestA1(){
  System.out.println("P ");
  this.init();
 }
 void init(){
  System.out.println("Q ");
 }
 public static void main(String argv[]){
  TestB1 d=  new TestB1();
 }
}
class TestB1 extends TestA1{
 int i =1;
 public TestB1(){
 super();
 System.out.println(i);
 }
 void init(){
  System.out.println("C ");
  i = 2;
  System.out.println(i +" ");
 }
}
输出
P
C
2
1

为什么?

|
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
}
}

|
这道题是一道关于多形性的题。
首先,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

|
这里涉及两个问题:
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()函数。


|
要清楚的理解为什么输出结果,有以下两个关键点。
1 java  中所有的成员方法都是 “虚函数”, 对象只调用真实对象中的对应方法。在本例子中super构造器调用的init方法实际上是调用TestB1的init方法。
2 构造器中的执行顺序
 调用super构造器
 初始化成员变量
 执行构造器的其他部分 


|
class T1 {
  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。

|
这是多态在构造函数中一个值得注意的地方。 
在构造函数中,要做尽量简单的动作,以避免你的程序存在漏洞。
就上面的例子,当别人从你的类中继承来,他就可以让你的类执行到自己设计的代码,而不是你所愿意的。
如果在构造函数中调用的是private的方法,那就不会有这些情况出现了。
建议看看与此相关的内容.

|
楼上的,我的理解...
执行程序时候,
遇到TestB1 d = new TestB1();
构建器申请内存把class TestB1 加载进来,并把内存区域擦干净,这是i(及其有关的成员变量)就是默认值0。
接着,因为 'extends TestA1', 所以不再进行动作,先加载 TestA1,也一样TestA1此时设置默认值。

为什么不先 初始化i = 10, 是考虑到可能这个初始化动作会受到父类初始化值的影响,所以要在父类初始化后再初始化子类的成员变量。

|
//xixi
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

|
to:   alula(alula) 
你这两段程序确实很好,他不仅说明了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完全可以不要。

|
迷惑——
我对下面程序用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的呢?关键是为什么!

|
一句话,this 指向的是testbB1

|
我认为ChrisZhang说的有道理:
this是对当前对象引用的一个句柄变量(是不是可以认为是一个常量呢),这里只构造了TestB1的一个对象,所以this.init()应该是指TestB1的方法。
至于去掉this之后仍然输出原结果,我想应该是方法重载的效果。

    
 
 
 
本站(WWW.)旨在分享和传播互联网科技相关的资讯和技术,将尽最大努力为读者提供更好的信息聚合和浏览方式。
本站(WWW.)站内文章除注明原创外,均为转载、整理或搜集自网络。欢迎任何形式的转载,转载请注明出处。












  • 相关文章推荐
  • 请路人甲来领分.谢谢你关于浏览器模态对话框的解答.
  • ChrisZhang(西楼明月),多谢你的解答。补送20分。
  • 一个奇怪的错误,请高手解答
  • 关于安装REDHAT9的几个问题,谢谢解答
  • 求高手解答菜鸟问题!!
  • gcc-plugin.h的问题,求解答。。。
  • 虚拟机里linux系统下输入l,k,m三个字母不能正常显示,求解答
  • 救命啊,高手解答,分不够再加
  • 一个相当实际的问题,希望来解答!
  • 紧急求援,限时解答(3小时内给分)
  • 大家都懒的回答我的吗?有人解答的话,送分100
  • 方法中的return()是返回到何处的,如何能获得,请解答
  • 有谁帮我解答一下?
  • 看看哪位高人能解答?
  • 新手关于Jbuilder6.0编辑器的光标定位使用问题,望高手解答
  • 真诚希望高手给予解答,关于UNIX扩展缓存的问题(100分相送)
  • 希望斑竹帮助解答!!在线等待
  • 能解答很多人疑问的好东西.
  • Redhat8.0中的乱码问题?(急需解答)
  • 简单的问题,请高手解答


  • 站内导航:


    特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

    ©2012-2021,,E-mail:www_#163.com(请将#改为@)

    浙ICP备11055608号-3