继承与多态

继承

继承是面向对象中一个非常独特的特性,避免了代码的重复提高了代码简洁性灵活性。比如我们要写birdwolf对象,不管是bird还是wolf都会吃喝拉撒,这些是他们的共同点,那么我们可以将这些共同点提取出来写成一个名为Animal的父类。然后让birdwolf 继承(extends)自Animal。

public class Animal{
    private String name;
    private int age;
    public Animal(String name,int age){
    	this.name=name;
    	this.age=age;
    }

    public void eat(){
    	System.out.println("I want to eat!");
    }

    public void sleep(){
    	System.out.println("I want to sleep!");
    }
  
    public int getAge(){
    	return this.age;
    }
}

class bird extends Animal{
    public bird(String name,int age){
    	super(name,age);
    }
}
class wolf extends Animal{
   public wolf(String name,int age){
       super(name,age);
    }
}

但从这里来看好像并没有什么不同,真正的继承从现在开始。Animal被称为父类birdwolf则被称为子类

super关键字

birdwolf的构造器里出现了super关键字。可是Animal却没有。其实Animal也有super关键字的,因为所有的类其实都继承自一个名为Object的类,虽然Animal没有写extends,java会默认的。super有超级的意思,而父类其实也有另外一种翻译叫超类super calss。那么super有什么用呢?super类似于一个传送门会把括号里的东西传送回父类,那么括号里的是啥呢?括号里就是对应的构造器的参数。比如在birdwolf

super(name,age)

会把nameage传送给Animal,然后在Animal里找对应的构造器。
可是上面才说了所有的对象其实都继承自Object,那Animal的super去哪了呢?如果子类构造器函数中没有指定执行父类中哪个构造函数,默认会调用父类中无参数构造函数。所有实际上Animal的构造器是这样的

public Animal(String name.int age){
    super();//super()必须放在构造器的第一行
    this.name=name;
    this.age=age;
}

而super()必须放在第一行也暗示着构造器的调用顺序,是层层往上回溯的。我们继续用一个例子说明

calss Some{
    Some(){
         System.out.println("调用Some");
    }
}
class Other extends Some{
    Other(){
        System.out.println("调用Other");
    }

    public static void main(String[] args){
    Other a=new Other();
    }
}
输出
调用Some
调用Other

我们在new一个Other的时候把Some的构造器也调用了一次。

重新定义

子类会得到父类的所有东西,private成员也会被继承只是无法直接使用除非父类提供了访问方法子类可以把继承得来的方法进行重写(override),比如birdAnimal继承的eat方法,我们可以进行override。其他部分需要保持一致,需要改变的只是方法体。

public void eat(){ 
    System.out.println("I want to eat fruits");
}

2020.3.20更正
private成员也会被继承只是无法直接使用,准确来说是无法继承private字段的,那么为什么又可以使用呢?(当然这个前提是你提供了getter/setter方法)因为JVM在内存中创建一个子类的时候会建立一个叫super区父类的东西会被放进去(并不是创建一个父类对象哦,只是有一块区域)。
拿一个被重写的方法举例

 @Override
 public String getName() {
  // TODO Auto-generated method stub
  System.out.println("这里是Son,来自getName");
  return super.getName();
 }
 //来自父类的getName
public String getName() {
  return name;
 }

return的写法就非常清晰的说明了问题,调用super区(即父类)的getName方法。证明了super区的存在

新写方法

很显然,bird会飞,但是Animal里并没有fly方法。而且wolf也并不会飞。所以我们不能把fly方法写进Animal如果写在Animal里的话,wolf也会继承fly方法的。而是把fly方法先进bird里,这样的事情是允许的,这也是继承灵活性的体现。

class bird extends Animal{
    public bird(String name,int age){
       super(name,age);
    }
    
    public void fly(){
       System.out.println("Blue sky!!!");
    }
}

final关键字

final关键字修饰的东西会被打上最后一次定义的标签,标明这个类,成员,方法都不可被继承。因为ta已经是最后一次定义了。


多态

什么叫多态?以抽象讲法解释,就是使用单一接口操作多种类型的对象。

//可以通过编译
bird a=new bird();
wolf b=new wolf();

Animal c=new bird();
Animal d=new wolf();

//不可以通过编译
bird e=new Animal();
wolf f=new Animal();

判断是否能通过编译,我们需要知道一种is-a的关系

is-a
is-a
is-a
is-a
bird
Animal
wolf
wolf
bird

很显然这是is a的关系,同样的我们用is-a来看看编译不通过代码是什么关系。

is-not-a
is-not-a
Animal
bird
wolf

可以看到是is not a的关系,所以编译不通过。

cast扮演(造型)

通过上面的is-a我们刚刚踏入多态的门栏,接下来我们看看多态的基础

Animal  a=new bird();
bird b=(bird)a;

因为我们在实例a的时候a是一个Animal,可是上面的图也说明Animal is not a bird所以我们用cast让a来扮演bird实际上a就是一个bird,所以编译通过。

wolf c=(bird)a;

这样的cast扮演则会出现错误,因为a实际上是个bird,只是在实例化时被打上了Animal的标签。
然鹅这并不是终极的单一接口操作多种类型的对象

单一接口操作多种类型的对象

在不知道多态之前,我们如果想知道birdwolfage就得分别给birdwolf写一个getAge方法

pubilc int getAge(){
	return this.age;
}

可是现在我们是学习了多态的java学习者了,那么该怎么使用多态呢?
我们可以直接在animalWord里写一个getAge方法

class animalWord{
	public static void getAge(Animal animal){
		System.out.println(animal.getAge());
	}

	public static void main(String[] args){
	bird a=new bird(10);
	wolf b=new wolf(20);

	getAge(a);
	getAge(b);
	}
}

尽管a是bird,b是wolf。但是都属于Animal,所以这是完全ok的。这个例子应该很好的诠释了单一接口操作多种类型的对象。我们用一个参数是一个animal类型的getAge方法。以后不管新增的fishsheep统统使用extends继承Animal就能用这个getAge方法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值