继承
-
概述
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
-
格式
通过extends关键字可以实现类与类的继承
class 子类名 extends 父类名 { }
单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类
eg:父类:
public class Animal {
public String name;
public String age;
public void eat() {
System.out.println("吃饭饭");
}
public void sleep() {
System.out.println("睡觉觉");
}
}
子类:(猫是动物的一种,有基础共同点)
public class Cat extends Animal{
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
测试类:
public class MyTest {
public static void main(String[] args) {
Cat cat = new Cat();
cat.name="小白";
cat.age="2";
cat.eat(); //继承了父类Animal的eat方法
cat.sleep(); //继承了父类Animal的sleep方法
cat.catchMouse();//cat自身的catchMouse方法
System.out.println(cat.name);
System.out.println(cat.age);
}
}
- 继承的好处
- 提高了代码的复用性
- 提高了代码的维护性
- 让类与类之间产生了关系,是多态的前提
-
继承的弊端
类的耦合性增强了。
- 继承的特点
- Java只支持单继承,不支持多继承。(只有一个父亲)
- Java支持多层继承(继承体系,即一个父亲也可以有一个父亲就是爷爷,儿子继承父亲,父亲继承爷爷,就相当于孙子也会继承爷爷的成员)
- 继承的注意事项
- 子类只能继承父类所有非私有的成员(成员方法和成员变量)
- 子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。
- 不要为了部分功能而去继承
-
子类中的成员变量和父类中的成员变量名称一样
在子类中访问一个变量的查找顺序(“就近原则”)
- 在子类方法的局部范围找,有就使用
- 在子类成员范围找,有就使用
- 在父类成员范围找,有就使用
- 如果还找不到,就报错
-
继承中成员方法关系
I:当子类的方法名和父类的方法名不一样的时候
II:当子类的方法名和父类的方法名一样的时候
通过子类调用方法:
1. 先查找子类中有没有该方法,如果有就使用
2. 再看父类中有没有该方法,有就使用
3. 如果没有就报错
super关键字
-
this和super的区别
this 代表的是本类对象的引用
super 代表的是父类存储空间的标识(可以理解成父类的引用,可以操作父类的成员)
- this和super的使用
-
调用成员变量
this.成员变量 调用本类的成员变量
super.成员变量 调用父类的成员变量
-
调用构造方法
this(…) 调用本类的构造方法
super(…) 调用父类的构造方法
-
调用成员方法
this.成员方法 调用本类的成员方法
super.成员方法 调用父类的成员方法
-
其实每一个构造方法的第一条语句默认都是:super(),即先访问初始化父类
因为,子类会继承父类中的数据,可能还会使用父类的数据。
所以,子类初始化之前,一定要先完成父类数据的初始化。
class Fu{
public int num = 10;
public Fu(){
System.out.println("fu");
}
}
class Zi extends Fu{
public int num = 20;
public Zi(){
System.out.println("zi");
}
public void show(){
int num = 30;
System.out.println(num); //30
System.out.println(this.num); //20
System.out.println(super.num); //10
}
}
class Test {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
输出:30(就近本方法中的num=30)、20(this.num即本类中的num=20)、10(super.num即父类中的num=10).
方法重写
-
概念:
子类中出现了和父类中一模一样的方法声明(方法名,参数列表,返回值类型),也被称为方法覆盖,方法复写。
-
应用:
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。
这样,即沿袭( super.call();重写方法中保留)了父类的功能,又定义了子类特有的内容。
//父类代码
public class Phone {
public Phone() {
System.out.println("构造方法执行了");
}
public void call() {
System.out.println("打电话 1000行代码");
}
public void send() {
System.out.println("发短信");
}
}
//子类代码
public class Iphone extends Phone{
public void palyGame(){
System.out.println("玩游戏");
}
@Override //注解 @Override 这个注解的作用,是用来检测此方法是不是重写父类的方法
public void call() { //同名同参重写
super.call(); //沿袭父类的功能
System.out.println("高清视频通话"); //子类特有功能
}
}
- 方法重写注意事项
- 父类中私有方法不能被重写(父类私有方法子类根本就无法继承)
- 子类重写父类方法时,访问权限不能更低(最好就一致)
- 父类静态方法,子类也必须通过静态方法进行重写(其实这个算不上方法重写,但是现象确实如此,其实只是执行了子类自己的静态方法而已)
final关键字
-
final修饰特点
修饰类: 被修饰类不能被继承
修饰方法: 被修饰的方法不能被重写
修饰变量: 被修饰的变量不能被重新赋值,因为这个量其实是一个常量
-
final关键字修饰局部变量
基本类型,是值不能被改变
引用类型,是地址值不能被改变
//final修饰类,此类不能被继承
final class EE{
}
//final修饰方法,此方法,不能被子类重写,但是可以让子类继承去用
class BB{
public final void show(){
System.out.println("父类的final修饰的方法,子类不能重写,子类可以继承");
}
}
//final修饰变量,此变量为一个常量,既然为常量,常量的值就不能再次被改变。
final int NUM=100;//自定义常量,常量名一般建议大写
多态
-
概述
某一个事物,在不同时刻表现出来的不同状态。
例如: Cat c=new Cat();
Animal a=new Cat();
猫可以是猫的类型。猫 m = new 猫();
猫也是动物的一种,也可以把猫称为动物。动物 d = new 猫();
- 多态前提
- 要有继承关系。
- 要有方法重写。 (其实没有也是可以的,但是如果没有这个就没有意义。)
-
要由父类引用指向子类对象。
父类 f = new 子类( );
- 多态中的成员访问特点
-
成员变量
编译看左边,运行看左边。
-
构造方法
创建子类对象的时候,会访问父类的构造方法,对父类的数据进行初始化。
-
成员方法
编译看左边,运行看右边。
(即父类中没有这个成员方法会报错编译失败,有的话编译成功,但是运行子类重写的方法)
-
静态方法
编译看左边,运行看左边。
(静态和类相关,算不上重写,所以,访问还是左边的)
-
public class MyTest {
public static void main(String[] args) {
Fu fu = new Zi();
//1.多态的形式来访问成员变量,编译看左边(父类),运行还是看左边(父类)。
int num = fu.num;
System.out.println(num);
//2.多态的形式来调用成员方法,如果子类有重写,编译看左边,运行看右边,当然子类没有重写该方法,那调用的还是父类的
fu.show();
//3.构造方法,多态的形式,还是先去调用父类的构造方法,先完成父类数据的初始化
//4.多态的形式调用静态方法,调用的还是父类的静态方法。
fu.hehe();
Fu.hehe();
Zi.hehe();
}
}
class Fu {
int num = 100;
public Fu() {
System.out.println("父类的构造方法执行了");
}
public void show() {
System.out.println("fu show");
}
public static void hehe() {
System.out.println("fu hehe");
}
}
class Zi extends Fu {
int num = 50;
public Zi() {
System.out.println("子类的构造方法执行了");
}
@Override
public void show() {
System.out.println("zi Show");
}
public static void hehe() {
System.out.println("zi hehe");
}
}
- 多态的好处
- 提高了代码的维护性(继承保证)
- 提高了代码的扩展性(由多态保证)
-
多态的弊端
不能使用子类特有的功能
解决弊端:把父类的引用强制转换为子类的引用。(向下转型)
Fu fu = new Zi(); //继承
fu.show(); //继承父类方法
Zi zi= (Zi) fu; //向下转型
zi.method(); //子类特有方法