您的位置:首页 > 其它

学习和使用继承时最先要清楚的三点

2004-03-30 19:16 633 查看
作者:qlampskyface

和作者联系:xiaozuidaizhi@sina.com



第一点:

那就是
1.如果该子类覆盖了父类的方法,那么该子类对象调用该方法时,被该方法修改的类级别变量是该子类的变量。
2.如果该子类没有覆盖父类方法,而直接调用父类的方法,那么被该方法修改的类级别变量是父类的变量。
1则如下例:
public class Temp{
public static void main(String args[]){
b bb = new b();
bb.fuqin();
}
}
class a{
public String s = "fuqin";
public void fuqin(){
System.out.println(s);
}
}
class b extends a{
public String s = "erzi";
public void fuqin(){
System.out.println(s);
}
}
//结果为erzi

2.则如下例:
public class Temp{
public static void main(String args[]){
b bb = new b();
bb.fuqin();
}
}
class a{
public String s = "fuqin";
public void fuqin(){
System.out.println(s);
}
}
class b extends a{
public String s = "erzi";
public void erzi(){
System.out.println(s);
}
}
//结果为fuqin
第二点:
那就是对“覆盖(override)”和“重载(overload)”以及重建的概念的清晰。
先声明一下:重建就是写一个新的方法。
如下例:
下面这个叫覆盖

public class Temp {
public static void main(String[] args) {
Sub sub = new Sub();
sub.plus(2);
System.out.println(sub.i);
}
}
class Super {
protected int i;
void plus(int i) {
this.i += i;
}
}
class Sub
extends Super {
protected int i = 1;
void plus(int i){
this.i=i+5;
}
}

下面这个叫重建,不是重载:
public class Temp {
public static void main(String[] args) {
Sub sub = new Sub();
sub.plus(2);
sub.plus(2,2);
System.out.println(sub.i);
System.out.println(((Super)sub).i);
}
}
class Super {
protected int i;
void plus(int i) {
this.i += i;
}
}
class Sub
extends Super {
protected int i = 1;
void plus(int i,int j){
this.i=i+j;
}
}
第三点:
那就是通常所说的“继承后使用多态”、“动态方法调度”、“运行时类型识别”了。先不要被上面的术语搞昏头哦:-)
可以总结为以下两条:
1.默认状态(和强制类型转换状态相区别)下,该对象(sub)只能调用父类方法和父类变量(调用该子类方法时会出现编译期错误)。此种情况下,还有两种不同的情况:
▲被调用方法是被该子类覆盖的方法,这时其实是显式调用父类方法,实际上是调用该子类方法和该子类变量,这时父类变量不能被该方法修改,被修改的是该子类变量。
▲被调用方法没有被该子类覆盖,这时是调用父类方法,父类变量可以被该方法修改。
看看下面的代码,注意1~5处。

public class Temp {
public static void main(String[] args) {
Super sub = new Sub();
System.out.println(sub.i);//打印结果为0----------------------------------------------1
sub.plus(3);//打印结果为Sub's plus.默认状态下伪调用被覆盖了的父类方法,
//实际调用该子类该方法------------------------------------------------------2
System.out.println(sub.i);//打印结果为0----------------------------------------------3
sub.print();//打印结果为Super.默认状态下调用没有被覆盖的父类方法
//实际就是本类(父类)方法-------------------------------------------------4
System.out.println(sub.i);//打印结果为5:---------------------------------------------5
}
}
class Super {
protected int i=0;
void plus(int i) {
this.i =3;
System.out.println("Super's plus");
}
void print(){
this.i=5;
System.out.println("Super");
}
}
class Sub
extends Super {
protected int i = 1;
void plus(int i) {
this.i = i + 8;
System.out.println("Sub's plus");
}
void plus(int i, int j) {
this.i = i + j;
}
}

2.强制类型转换状态下【注1】,该对象(sub)既可以调用该子类方法,又可以调用没有被覆盖的父类方法。
看看下面的代码,注意6、7处:

public class Temp {
public static void main(String[] args) {
Super sub = new Sub();
((Sub)sub).plus(3);//调用方法时强制转换----------------------------------------------6
((Sub)sub).print();//调用没有被覆盖的父类方法,改变父类变量---------------7
}
}

class Super {
protected int i=0;
void plus(int i) {
this.i =3;
System.out.println("Super's plus :"+this.i);
}
void print(){
this.i=5;
System.out.println("Super's print");
}
}
class Sub
extends Super {
protected int i = 1;
void plus(int i) {
this.i = i + 8;
System.out.println("Sub's plus :"+this.i);
}
}

【注1】对父类强制转换的结果和默认状态下是相同的,即使是被覆盖的方法,以父类做强制转换后的结果仍是实际上调用了该子类方法和该子类变量。所以,这里只讨论对该子类强制转换。
对第三点小结如下:
1.如果要想调用该子类的覆盖了父类的方法,可以在默认状态下调用,也可以在强制转换后调用。因为无论是在默认状态下,还是用父类去做强制转换调用,或者是用该子类去做强制转换调用,结果都是一样的,即调用被覆盖的该子类的方法;
2.如果要想调用父类的没有被该子类覆盖的方法,可以在默认状态下调用,也可以在被该子类强制转换后调用。都是一样的。
3.如果要想调用父类的被该子类覆盖的方法,对不起,这种情况下你得不到,不过可以通过“父类 对象名 = new 父类()”的普通创建方式得到。
4.如果要想调用父类变量(属性),对于所有的父类变量(属性),在默认状态下即可调用;对于没有被该子类覆盖的变量(属性),也可以在被子类强制转换后调用;
5.如果要想调用该子类特有的变量(属性),则只能在用该子类强制状态的情况下调用。
6.如果要想调用该子类特有的方法,则只能在用该子类强制状态的情况下使用。
下面的例子混合了上述情况,体验一下。

public class Temp {
public static void main(String[] args) {
Super sub = new Sub();
//调用父类特有的方法
System.out.println("父类特有的方法");
sub.print();
((Super)sub).print();
((Sub)sub).print();
//调用父类特有的变量(属性)
System.out.println("父类特有的变量(属性)");
System.out.println(sub.supown);
System.out.println(((Sub)sub).supown);
//调用被覆盖的父类的方法
System.out.println("被覆盖的父类的方法");
Super sup = new Super();
sup.plus(3);
//调用被覆盖了的父类的变量(属性)
System.out.println("被覆盖了的父类的变量(属性)");
System.out.println(sub.i);
System.out.println(sub.both);
//调用子类特有的方法
System.out.println("子类特有的方法");
((Sub)sub).reduce(3);
//调用子类特有的变量(属性)
System.out.println("子类特有的变量(属性)");
System.out.println(((Sub)sub).subown);
//调用覆盖了父类的子类的方法
System.out.println("覆盖了父类的子类的方法");
sub.plus(3);
((Sub)sub).plus(3);
((Super)sub).plus(3);
//调用被覆盖的子类的方法
System.out.println("覆盖了父类的子类的变量(属性)");
System.out.println(((Sub)sub).i);
System.out.println(((Sub)sub).both);
}
}

class Super {
protected int i = 0;
String both="Super's both",supown="Super's own supown";
void plus(int i) {
System.out.println("Super's plus");
}
void print() {
System.out.println("Super's own print");
}
}

class Sub
extends Super {
protected int i = 1;
String both="Sub's both",subown="Sub's own subown";
void plus(int i) {
System.out.println("Sub's plus");
}

void plus(int i, int j) {
System.out.println("Sub's own plus");
}

void reduce(int i) {
System.out.println("Sub's own reduce");
}
}
结果如下:
父类特有的方法
Super's own print
Super's own print
Super's own print
父类特有的变量(属性)
Super's own supown
Super's own supown
Super's own supown
被覆盖的父类的方法
Super's plus
被覆盖了的父类的变量(属性)
0
Super's both
子类特有的方法
Sub's own reduce
子类特有的变量(属性)
Sub's own subown
覆盖了父类的子类的方法
Sub's plus
Sub's plus
Sub's plus
覆盖了父类的子类的变量(属性)
1
Sub's both
对第三点总结如下:
通过以上的例子,我们可以得出以下总结:
对于以这种方式创建的对象来说,除了被子类[/b]
覆盖的父类方法外,它能访问子类和父类的其[/b]
余全部属性及方法。对子类的其余部分调用要[/b]
在强制转换后进行(除去继承自父类的方法)[/b][/b]
请看到的朋友评论!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: