一、继承
1.概念
继承是定义一种的新的类型,从已有的类中吸收成员变量和方法,
新的类型可以添加新的方法和成员变量。
被吸收的类叫作 父类,也叫超类、基类
新类叫作 子类,也叫派生类
父类是子类泛化的过程
优点:这种方式可以提高代码的复用性,缩短开发周期,减少开发费用。
2.定义
语法格式:
修饰词 class 类名 extends 父类类名
继承是通过关键字extends体现的
3.继承中的构造器
子类不能继承父类的构造器,但子类的构造器可以调用父类的构造器
语法:super(有参传参);
作用:给继承过来的成员变量赋值
super()与this()的区别
相同点:
都是调用构造器,而且必须放在首行首句,所以不能共存在一个构造器
不同点:
super()是调用父类的构造器
this()是调用本类中其他构造器
4.特性
1)传递性:
B类型继承了A类型的特征,C类型继承了 B类型的特征。
C类型也间接继承了A类型的特征
2)单继承:
一个子类只能继承一个父类。但是一个父类可以有多个子类
1.8版本以后可以多继承
5.方法的重写
1)定义:
在继承时,子类可以重新编写与父类中方法名相同,参数列表相同的方法
2)规则:
(1)父子类关系,方法名相同,参数列表相同
(2)返回值类型可以相同,也可以不同。
不同的话,子类方法的返回值类型必须是父类方法的返回值类型的子类
(3)修饰词可以不变,或者可以比父类的修饰权限更大
6.父类对象引用子类对象
如:
Animal a = new GoldFish();
Animal类型的变量a引用了子类型GoldFish的对象
变量能调用方法与成员变量
方法:
编译期: 变量只能调用出本类型中的方法
运行期: 变量调用出方法执行逻辑与对象的类型有关
成员变量:
变量调用出的成员变量一定是本类型中的成员变量
public class TestAnimal {
public static void main(String[] args) {
GoldFish f1 = new GoldFish();
f1.age = 1;// 养了一年
f1.isWater = true;
f1.color = "金色";
System.out.println(f1);
Shark s1 = new Shark(5, true, 100);
System.out.println(s1);
BabyFish b1 = new BabyFish(1, true, 1, "小强");
System.out.println(b1);
//父类变量引用子类对象
Animal a = new GoldFish();
System.out.println(a);
}
}
class Animal {
int age;//年龄
}
class Fish extends Animal {
boolean isWater;//是否会水
}
class GoldFish extends Fish {
String color;//颜色
public String toString() {
return "年龄:" + age + " 是否会水:" + isWater + " 颜色:" + color;
}
}
class Shark extends Fish {
int size;//体型
public Shark(int age, boolean isWater, int size) {
this.age = age;
this.isWater = isWater;
this.size = size;
}
public String toString() {
return "年龄:" + age + " 是否会水:" + isWater + " 尺寸:" + size;
}
}
class BabyFish extends Fish {
int size;
String name;
public BabyFish(int age, boolean isWater, int size, String name) {
this.age = age;
this.isWater = isWater;
this.size = size;
this.name = name;
}
public String toString() {
return "年龄:" + age + " 是否会水:" + isWater + " 尺寸:" + size + " 名字:" + name;
}
}
7.在创建子类对象时,在内存中会不会产生父类对象??
答案1: 会产生,没有父类对象,哪来的子类对象
答案2: 不会产生,创建子类对象时,子类对象的成员变量包含两部分:
一部分为从父类中继承过来的
在成员变量前有默认的super.
一部分是自己本类中的
在成员变量前有默认的this.
如果子类中独有的与继承过来的成员变量重名时,必须
显式指定使用super.或者是this.
如果子类中没有与继承过来的成员变量相同名时,我们可以
隐式不写,或者使用super.与this.其中任意一个。
为了避免不必要的麻烦,子类的成员变量尽可能不要与父类的
成员变量同名
二、多态
1.向上造型
父类型的变量引用子类型的对象
(1)父类型的变量指向不同的子类型对象,调用的功能有不同的实现
Animal a = new Dog();//父类变量a 实例了一个Dog对象
a.noise();//变量a 调用了noise()方法,运行时,实现的是Dog类中noise()
a = new Cat();//变量a 重新实例了一个Cat对象
a.noise();//变量a 调用了noise()方法,运行时,实现的时Cat类中noise()
(2)不同的父类型的变量指向同一个对象有不同功能
Door d = new Door(); //变量d 实例了一个Door对象
d.theftproof();//防盗
d.openDoor();//开门
Inter a = d;//接口a 指向了变量d
a.theftproof();//变量a 实现的是d的防盗
2.向下造型
将父类型(接口)的变量赋给子类型或者其他父类型(接口)的变量
Animal a = new Dog();
Dog dog = (Dog)a;
dog.eat();
Cat cat = (Cat)a;//编译通过,运行时,造型异常,
//因为变量a的类型已经变成Dog,而Dog和Cat没有关系
cat.catch();
3.造型异常
运行期间有可能会发生类造型异常:java.lang.ClassCastException
为了避免出现异常:我们需要使用instanceof关键字来判断对象是不是要转成的类型