向上转型

向上转型是用父类的引用指向子类的对象。即方法区中存放的是父类的说明,但堆中实际存储的是子类的对象。而父类创建的对象方法区中是父类的说明,堆中存储的是父类的对象。其实这个上转型我们经常用到的,比如List,我们一般用的是List list=new ArrayList();

当一个儿子长大成人娶妻生子之后,他便“向上转型”为一个父亲了,他除了非常私有的(private)一些情况保持不变外(只要变量名和父亲的不一样),如姓名,老婆的名字等等外,其他的属性(public,protected,friendly)都成为一个标准的父亲应有的属性(被覆盖了),如对家庭的责任感,由做儿子时的“低”变为了父亲应有的“高”;自由的程度,由作儿子时的“高”变为了作父亲后的“低”。而他作儿子时一些特有的(不属于父亲应有的或者说父类没有的)作为(方法)在其成为父亲后便被舍弃了,如恣意妄为,夜不归宿等等。而正常的行为,比如挣钱的方法,每个父亲肯定不尽相同,作son时的方法也就保存了下来(覆盖了父类的方法)他有一套自己的做事方法,但这套方法里应有的属性就如父亲的标准属性一样子类想用自己的方法,只能创建一个子类,用子类来执行方法。

Java代码  

class Foo {  

 public int a;  

 public Foo() { a = 3; }  

 public void addFive() { a += 5; }  

}  

public class Bar extends Foo{  

    public int a;  

    public Bar() { a = 8; }  

    public void addFive() { this.a +=5; }  

      

    public static void main(String[] args) {  

        Foo foo = new Bar();  

         foo.addFive();  

         System.out.println("Value: "+ foo.a); //3 

    }  

}  
与java得多态有关 方法可以多态重载,但属性不能 

public int addFive() {  

  super.a += 5;  

}  

Java代码  

class Foo {  

    public int a;  

    public Foo() {  

        a = 3;  

    }

    public int addFive() {  

        a += 5;  

        return a;  

    }  

    public int getA() {  

        return a;  

    }  

public class Bar extends Foo {  

    public int a;  

  

    public Bar() {  

        a = 8;  

    }  

  

    public int addFive() {  

        this.a += 5;  

        return a;  

    }  

    public int getA() {  

        return a;  

    }

    public static void main(String[] args) {  

        Foo foo = new Bar();  

        //调用的是子类中的方法  

        System.out.println(foo.getA());  

        //直接调用父类中的a  

        System.out.println("Value: " + foo.a);  

        //调用的是子类中的方法  

        System.out.println(foo.addFive());          

    }  

}  

输出结果: 

Value: 3 
13 

class Base{  
   public int a;  
   public static int b;  
   public Base(){  
     a=1;  
     b=1;  
   }  
   public void addFivetoa(){  
    a+=5;  
   }  
   public static void addSixtob(){  
    b+=6;  
   }  
}  
public class Son extends Base{  
  public Son(){  
   a=2;  
   b=2;  
  }  
public void addFivetoa(){  
   a+=7;  
  }  
public static void addSixtob(){  
   b+=8;  
}  
public static void main(String args[]){  
Son son = new Son();  
Base base = son;  
base.addFivetoa();  
base.addSixtob();  
System.out.println(base.a);//9 
System.out.println(base.b);//8  
System.out.println(son.a);//9 
System.out.println(son.b);//8  
}  
}  

过程:先初始化Base的b为0,然后调用父类的构造方法初始化a=1,b=1,然后调用Son的构造方法初始化a=2,b=2;//按实际得到
base.addFivetoa();//a=7;调用子类的 
base.addSixtob();//b=8;调用父类的静态方法;

son.addSixtob();//b=10;调用子类的静态方法;
属性是不能多态的,静态方法也不能多态。 
衍生: 
Java代码 
   public int a;  
   public static int b;  
   public Base(){  
     a=1;  
     b=1;  
   }  
   public void addFivetoa(){  
    a+=5;  
   }  
   public static void addSixtob(){  
    b+=6;  
   }  
}  
public class Son extends Base{  
  public int a;  
  public static int b;  
  public Son(){  
   a=2;  
   b=2;  
  }  
public void addFivetoa(){  
   this.a+=7;  
  }  
public static void addSixtob(){  
   b+=8;  
}  
public static void main(String args[]){  
Son son = new Son();  
Base base = son;  
base.addFivetoa();  
base.addSixtob();  
System.out.println(base.a);//1  
System.out.println(base.b);//7  
System.out.println(son.a);//9  
System.out.println(son.b);//2  
}  
}

过程:先初始化Base的b为0,然后调用父类的构造方法初始化a=1,b=1,然后调用Son的构造方法初始化子类中的a和b,a=2,b=2;//父类的a和b 与子类的是不同
base.addFivetoa();//调用子类的方法,son.a=7 
base.addSixtob();//调用父类的方法,base.b=1+6=7 ,(子类的没有变化)
剩下的base.a和son.b都没有变化所以分别为1,2。 

父类的除private方法以外的方法都被子类所继承.并且覆盖但是属性却没有被覆盖,方法是重写,属性不能重写,所以foo.a访问的是父类的属性,而 foo.addFive(); 调用的是子类覆盖父类的 addFive()方法,既然调用的是子类的方法,所以这个方法修改的是子类属性的值。

Foo foo = new Bar(); 此时,new的虽然是Bar()的实例,但是在内存看到的只是父类的属性,与子类的属性无关。所以,a的值为3。

Foo foo = new Bar();    //foo.a=3,bar.a=8互不相碍

foo.addFive(); //bar.a=8+5父类的方法被覆盖了,所以foo.a没有变化 

System.out.println("Value: "+ foo.a);  //foo.a=3,bar.a=13  


这也是隐藏域,提供setter/getter的一个原因吧。

父类中的a和子类中的a是两个不同的成员变量,同时存在的,不会出现覆盖的现象。 
Foo foo = new TestEYE1();  //调用父类构造。 
此时,foo虽然是TestEYE1,但是它是被当作Foo来执行的。 
所以它的一些TestEYE1属性全部都被禁用。但是堆中存在这些属性。 
当调用foo.addFive()方法时,由于子类对父类的方法重写,执行子类的方法, 
this.a +=5;  其中this可以不加的,默认的就是调用本类(TestEYE1)的成员变量。 
最后打印foo.a,foo虽然有两个a成员变量,但是因为它现在是Foo身份,所以子类的a是禁用的,但是它还是存在的,只要身份变成TestEYE1,就会打印子类的a属性。看第二次打印的结果就知道了。 
System.out.println("Value: "+ foo.a);   
System.out.println("Value: "+ ((TestEYE1)foo).a);   

因为对计算机而言,这两个成员变量就算是名字相同,它也认为不同的。 
注意:这句  Foo foo = new Bar();创建了一个Bar对象 
一个对象创建的过程分成4步: 
1.分配空间 
2.递归创建父类对象:创建了父类的属性和方法,并没有创建父类对象
3.调用本类构造方法  
4.初始化本类属性;  

有点值得关注的是。如果addFive返回类型改成int 之后 
你打印System.out.println(foo.addFive()); 的值是18,而不是13。

在子类中调用父类同名属性可以这样写super.a,super不能在静态的主方法里使用

子类重写父类方法会造成父类方法被覆盖,而属性却不是这样; 
          Foo foo = new Bar(); 
程序运行到这一部,是实例化一个子类对象交给父类引用,在这个对象中有两个属性a,父类的属性a=3和子类自己的a=8  ,而addFive方法只有一个,那就是子类重写的addFive方法;foo.addFive();  
这一步调用的是子类重写后的方法,所以在这里值发生改变的是子类的a而不是父类的,这时候子类的a=8+5=13,而父类的a=3没有变。 
         System.out.println("Value: "+ foo.a); 
foo是一个父类的引用,foo.a是父类的a当然是等于3了  

Foo foo = new Bar();   
像这种upcast(向上造型) 
1.域:调用父类属性 (子类的属性也存在)
2.方法:调用子类方法  

引用

详情见:thinking in java 4th 的例子 
中文版156 
英文版290

Foo foo = new Bar();  //实际上实例化Foo 类中的a = 3; 
foo.addFive();  //实际上调用了Bar类的方法 
如果是想得到 5 + 8 = 13的结果,就封装a字段 
class Foo { 
private int a; 
public Foo() { a = 3; } 
public void addFive() { a += 5; } 
public int getA() { 
return a; 


public class Bar extends Foo{ 
    private int a; 
    public Bar() { a = 8; } 
    public int getA() { 
return a; 

@Override 
    public void addFive() { a +=5; } 
    public static void main(String[] args) { 
     Foo foo = new Bar(); 
     foo.addFive(); 
     System.out.println("Value: "+ foo.getA()); //getA()也是调用子类的
    } }

这个是java类初始化问题,每个子类对象都含有父类对象,所以要先调用父类的构造函数构造一个父类对象。 
Java类初始化顺序,构造链表 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值