一、多态
1.多态概述
某一个事物,在不同时刻表现出来的不同状态。
举例:
//猫可以是猫的类型。
猫 m = new 猫();
//同时猫也是动物的一种,也可以把猫称为动物。
动物 d = new 猫();
2.多态前提
①要有继承关系
②要有方法重写[没有则没有意义 ]
③要有父类引用指向子类对象
父 f = new 子();
3.多态访问成员变量
①成员变量
-编译看左边,运行看左边
②构造方法
-创建子类对象时,访问父类的构造方法,对父类的数据进行初始化。
③成员方法
-编译看左边,运行看右边
④静态方法
-编译看左边,运行看左边
多态继承中的内存图解
4.多态的优势和弊端
优势
①提高了代码的维护性(继承)。
②提高了代码的扩展性。
弊端
不能访问子类特有功能。
5.对象间的转型
向上转型
从子到父.父类引用指向子类对象
Fu f = new Zi();
向下转型
从父到子.父类引用转为子类对象
Zi z = (Zi)f;
转型理解实例:
class 孔子爹
{
public int age = 40;
public void teach() {
System.out.println("讲解JavaSE");
}
}
class 孔子 extends 孔子爹
{
public int age = 20;
public void teach() {
System.out.println("讲解论语");
}
public void playGame() {
System.out.println("英雄联盟");
}
}
//Java培训特别火,很多人来请孔子爹去讲课,这一天孔子爹被请走了
//但是还有人来请,就剩孔子在家,价格还挺高。孔子一想,我是不是可以考虑去呢?
//然后就穿上爹的衣服,带上爹的眼睛,粘上爹的胡子。就开始装爹
//向上转型
孔子爹 k爹 = new 孔子();
//到人家那里去了
System.out.println(k爹.age); //40
k爹.teach(); //讲解论语
//k爹.playGame(); //这是儿子才能做的
//讲完了,下班回家了
//脱下爹的装备,换上自己的装备
//向下转型
孔子 k = (孔子) k爹;
System.out.println(k.age); //20
k.teach(); //讲解论语
k.playGame(); //英雄联盟
多态中的对象变化内存图解
思考题
思考1:
看程序写结果:先判断有没有问题,如果没有,写出结果
class A {
public void show() {
show2();
}
public void show2() {
System.out.println("我");
}
}
class B extends A {
/*
public void show() {
show2();
}
*/
public void show2() {
System.out.println("爱");
}
}
class C extends B {
public void show() {
super.show();
}
public void show2() {
System.out.println("你");
}
}
public class DuoTaiTest {
public static void main(String[] args) {
A a = new B();
a.show();
B b = new C();
b.show();
}
}
答:
输出 “爱你”
多态的成员访问特点:
-方法:编译看左边,运行看右边。
继承的时候:
-子类中有和父类中一样的方法,叫重写。
-子类中没有父亲中出现过的方法,方法就被继承过来了。
二、抽象类
1.抽象类概述
在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。
2.抽象类特点
①抽象类和抽象方法必须用abstract关键字修饰。
②抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类。
③ 抽象类不能实例化
-抽象类有构造方法,但是不能实例化,用于子类访问父类数据的初始化。
//抽象类的实例化其实是靠具体的子类实现的。是多态的方式。
Animal a = new Cat();
④抽象的子类
-如果不想重写抽象方法,该子类是一个抽象类。
-重写所有的抽象方法,这个时候子类是一个具体的类。
3.抽象类的成员特点
-成员变量:既可以是变量,也可以是常量。
-构造方法:有,用于子类访问父类数据的初始化。
-成员方法:既可以是抽象的,也可以是非抽象的。
抽象类的成员方法特性:
A:抽象方法 强制要求子类做的事情。
B:非抽象方法 子类继承的事情,提高代码复用性。
思考题
思考1:
一个类如果没有抽象方法,可不可以定义为抽象类?
如果可以,有什么意义?
答:可以,不让创建对象。
—————————————————————————
思考2:
abstract不能和哪些关键字共存?
答:private-冲突、final-冲突、static-无意义。
—————————————————————————
三、接口
1.接口概述
为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现。
2.接口特点
①接口用关键字interface表示
格式:interface 接口名 {}
②类实现接口用implements表示
格式:class 类名 implements 接口名 {}
③接口不能实例化
按照多态的方式来实例化。
多态的几种方式:
-具体类多态(几乎没有)
-抽象类多态(常用)
-接口多态(最常用)
④接口的子类
-可以是抽象类。但是意义不大。
-可以是具体类。要重写接口中的所有抽象方法。(推荐方案)
3.接口成员特点
成员变量
只能是常量,默认修饰符 public static final。
构造方法
没有,因为接口主要是扩展功能的,而没有具体存在。
成员方法
只能是抽象方法,默认修饰符 public abstract。
类与类,类与接口以及接口与接口的关系
类与类:
继承关系,只能单继承,但是可以多层继承。
类与接口:
实现关系,可以单实现,也可以多实现。还可以在继承一个类的同时实现多个接口。
接口与接口:
继承关系,可以单继承,也可以多继承。
抽象类和接口的区别
成员区别
抽象类 变量,常量;有抽象方法;抽象方法,非抽象方法
接口 常量;抽象方法
关系区别
类与类 继承,单继承
类与接口 实现,单实现,多实现
接口与接口 继承,单继承,多继承
设计理念区别
抽象类 被继承体现的是:”is a”的关系。共性功能
接口 被实现体现的是:”like a”的关系。扩展功能
示例:
/*
教练和运动员案例
乒乓球运动员和篮球运动员。
乒乓球教练和篮球教练。
为了出国交流,跟乒乓球相关的人员都需要学习英语。
分析,这个案例中有哪些抽象类,哪些接口,哪些具体类。
*/
//定义一个说英语的接口
interface SpeakEnglish {
//说英语
public abstract void speak();
}
//定义人的抽象类
abstract class Person {
private String name;
private int age;
public Person() {}
public Person(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//睡觉
public void sleep() {
System.out.println("人都是要睡觉的");
}
//吃饭
public abstract void eat();
}
//定义运动员抽象类
abstract class Player extends Person {
public Player() {}
public Player(String name,int age) {
super(name,age);
}
//学习
public abstract void study();
}
//定义教练抽象类
abstract class Coach extends Person {
public Coach() {}
public Coach(String name,int age) {
super(name,age);
}
//教
public abstract void teach();
}
//定义乒乓球运动员具体类
class PingPangPlayer extends Player implements SpeakEnglish {
public PingPangPlayer(){}
public PingPangPlayer(String name,int age) {
super(name,age);
}
//吃
public void eat() {
System.out.println("乒乓球运动员吃大白菜,喝小米粥");
}
//学习
public void study() {
System.out.println("乒乓球运动员学习如何发球和接球");
}
//说英语
public void speak() {
System.out.println("乒乓球运动员说英语");
}
}
//定义篮球运动员具体类
class BasketballPlayer extends Player {
public BasketballPlayer(){}
public BasketballPlayer(String name,int age) {
super(name,age);
}
//吃
public void eat() {
System.out.println("篮球运动员吃牛肉,喝牛奶");
}
//学习
public void study() {
System.out.println("篮球运动员学习如何运球和投篮");
}
}
//定义乒乓球教练具体类
class PingPangCoach extends Coach implements SpeakEnglish {
public PingPangCoach(){}
public PingPangCoach(String name,int age) {
super(name,age);
}
//吃
public void eat() {
System.out.println("乒乓球教练吃小白菜,喝大米粥");
}
//教
public void teach() {
System.out.println("乒乓球教练教如何发球和接球");
}
//说英语
public void speak() {
System.out.println("乒乓球教练说英语");
}
}
//定义篮球教练具体类
class BasketballCoach extends Coach {
public BasketballCoach(){}
public BasketballCoach(String name,int age) {
super(name,age);
}
//吃
public void eat() {
System.out.println("篮球教练吃羊肉,喝羊奶");
}
//教
public void teach() {
System.out.println("篮球教练教如何运球和投篮");
}
}
class InterfaceDemo {
public static void main(String[] args) {
//测试运动员(乒乓球运动员和篮球运动员)
//乒乓球运动员
PingPangPlayer ppp = new PingPangPlayer();
ppp.setName("王浩");
ppp.setAge(33);
System.out.println(ppp.getName()+"---"+ppp.getAge());
ppp.eat();
ppp.sleep();
ppp.study();
ppp.speak();
System.out.println("----------------");
//篮球运动员
BasketballPlayer bp = new BasketballPlayer();
bp.setName("姚明");
bp.setAge(34);
System.out.println(bp.getName()+"---"+bp.getAge());
bp.eat();
bp.sleep();
bp.study();
//bp.speak(); //没有该方法
}
}
案例分析图: