为什么需要有继承?
当定义多个类时,发现有些类具有相同的属性和行为,那么就可以根据这些属性和行为单独创建一个类,称为父类。
那些具有特有的行为和属性存在于子类中。
注意:
一个父类可以有多个子类
但一个子类只能有一个父类
在Java继承体系当中,所有类的最终父类都是Object
如果我们在定义一个类的时候,没有显著声明父类的时候 那么该类的父类默认是Object
//继承格式
class 子类名 extends 父类名{}
- extends关键字(继承)
- super关键字(调用父类构造函数或成员变量)
- abstract关键字(抽象)
下面是一个简单例子:
有四个类分别为Animal类、Person类、Dog类、Cat类,其中的后三个类都是Animal类的子类,因为它们有共同的属性(如:名字name、眼睛numEyes、腿numLegs),有共同的行为(如:eat() )
特有行为:
- Person speak() feed()
- Dog lookHouse()
- Cat catchMouse()
class Animal{ //父类
public String name;
public static int numEyes=2;//眼睛数量为静态变量,为2,是Animal类共有的
public int numLegs;
public Animal() {
this(4); //this()指向带参构造函数
}
public Animal(int legs) {
numLegs=legs;
}
public abstract void eat(){} //抽象函数
}
//Animal的子类
class Person extends Animal{
public Person() {
super(2);//调用父类带参构造函数
}
public void speak(){
System.out.println("说话!");
}
public void feed(Animal animal){}//下文介绍该行为
public void eat(){ //属于Override(重写)
System.out.println("吃饭!");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("吃狗粮!");
}
public void lookHouse(){
System.out.println("看家ing");
}
}
class Cat extends Animal{
public void eat(){
System.out.println("吃鱼!");
}
public void catchMouse(){ //Cat类特有的行为
System.out.println("捉老鼠!");
}
注意:
子父类中构造函数的特点:
现象:子类的构造函数在调用运行的时候 先执行父类的构造函数
在子类的构造函数当中,有一句默认的super(...)隐藏了,而且这句代码必须是在第一行
对super的调用必须是构造器中的第一个(why???)既然子类继承自父类 那么必然会继承到父类当中的一些数据
所以,在子类构造函数之中,必须先让父类把这些数据进行一些初始化才能继承给子类父类的构造函数被调用,但不代表父类就被创建对象了!
所以this是当前对象的引用,而super不是父类对象的引用,而是父类空间的引用
重写@Override
函数重写:在子父类中,同名函数,返回值相同,函数参数数量、类型相同,且子类权限大于等于父类权限,仅仅函数体不同。
注意:
父类函数权限为private,则无法继承,也就无重写的说法。
抽象类abstract
当一个类的子类有着共同的行为,但是各子类具体行为又是有不同特点的,那么这个父类行为无需写函数体,只需声明该方法即可,该方法称为抽象函数(用来被重写)。该类就为抽象函数。
注意:
抽象类必须作为父类,抽象类就等着被继承
抽象类不能创建对象,因为对象是具体的,抽象类不是具体的
abstract这个关键字不能和那些关键字共存?
private 抽象函数就等着被子类重写实现呢!
static 静态是优先于对象存在的,在加载静态数据的时候 肯定是具体的数据
类名.抽象函数 很尴尬!
如果抽象函数可以被静态 那么我们还需要对象干什么?
abstract class 类名{
成员变量
......
public abstract void 方法名(); //抽象函数
}
多态
什么是多态?多态就是指一个对象可以有多重状态
例:
小明需要想养一只动物,小明的角度而言,养的对象的类为Animal类
该动物可以是猫,可以是狗,那么从该角度而言,对象就为Cat类、Dog类。
可以这样创建对象:
父类名 对象名=new 子类名(...);
该对象就可以作为父类来使用,对代码的功能进行了扩展
特点:
只能调用父类的方法或者子类重写的方法,不能调用子类特有的方法
只能访问父类的成员变量
instanceof
对象名 instanceof 类名//(返回值类型boolean)
判断一个对象是否属于该类