11-01接口的概念
- 接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的”类”。
- 接口只描述所应该具备的方法,并没有具体实现,具体的实现由接口的实现类(相当于接口的子类)来完成
- 这样将功能的定义与实现分离,优化了程序设计。
11-02接口的定义
- 接口定义时需要使用interface关键字。
- 定义接口所在的仍为.java文件,编译后仍然会产生.class文件。
- 格式:
public interface 接口名 {
//public abstract 返回类型 方法 ();
public abstract void funtion();
//public static final 类型 变量名 = 值 ;
public static final int x = 5;
}
- 接口中的方法均为公共访问的抽象方法,接口中无法定义普通的成员变量
11-03接口的实现类
- 类与接口的关系为实现关系,即类实现接口。实现的动作类似继承,只是关键字不同,实现使用implements。实现类仍然需要重写方法以实现具体的功能。
- 格式
class 类 implements 接口 {
重写接口中方法
}
11-04接口中成员变量的特点
- 没有变量,都是常量,其值不能改变。
- 固定定义格式: public static final 数据类型 变量名 = 值
public 权限
static 可以被类名直接.调用
final 最终,固定住变量的值 - public static final 修饰符,在接口的定义中,可以省略不写,三个修饰符,还可以选择性书写,但是, 写不写都默认存在
11-05接口中成员方法的特点
- 固定定义格式: public abstract 返回值类型 方法名(参数列表)
- 修饰符 public abstract 可以不写,选择性书写,但是,写不写,都有
11-06实现类还是一个抽象类
- 子类必须覆盖掉接口中所有的抽象方法后,子类才可以实例化。否则子类是一个抽象类。
- 实现类也声明为抽象类,那么实现类可以不重写接口中的抽象方法。
11-07类和接口的多实现
- 接口最重要的体现:解决多继承的弊端。将多继承这种机制在java中通过多实现完成了。
- 弊端:多继承时,当多个父类中有相同功能时,子类调用会产生不确定性。
- 核心原因就是在于多继承父类中功能有主体,而导致调用运行时,不确定运行哪个主体内容。接口中的功能都没有方法体,由子类来明确
4.例子
public interface Fu1{
void show1();
}
public interface Fu2{
void show2();
}
public class Zi implements Fu1,Fu2 { // 多实现。同时实现多个接口。
public void show1(){}
public void show2(){}
}
11-08类在继承类的同时实现多接口
1.子类通过继承父类扩展功能,通过继承扩展的功能都是子类应该具备的基础功能。如果子类想要继续扩展其他类中的功能,通过实现接口来完成。
2.代码
public class Fu {
public void show(){}
}
public interface Inter {
pulbic abstract void show1();
}
public class Zi extends Fu implements Inter {
public void show1() {
}
}
11-09接口的多继承
- 多个接口之间可以使用extends进行继承。
- java中有没有多继承?
在类中没有,在接口中有 - 代码
public interface Fu1{
void show();
}
public interface Fu2{
void show1();
}
public interface Fu3 extends Fu1,Fu2{
void show2();
}
11-10接口思想
- 电脑上留有很多个插口,而这些插口为什么能插入相应的设备呢?
* 主要原因是这些设备在生产的时候符合了这个插口的使用规则,否则将无法插入接口中,更无法使用。发现这个插口的出现让我们使用更多的设备。 - 接口在开发中的好处
* 1、接口的出现扩展了功能。
* 2、接口其实就是暴漏出来的规则。
* 3、接口的出现降低了耦合性,即设备与设备之间实现了解耦。
11-11接口和抽象类的区别
自身拥有的功能叫抽象类,额外拥有的功能叫接口
1.相同点:
都位于继承的顶端,用于被其他类实现或继承;
都不能直接实例化对象;
都包含抽象方法,其子类都必须覆写这些抽象方法;
2.区别:
抽象类为部分方法提供实现,避免子类重复实现这些方法,提高代码重用性;接口只能包含抽象方法;
一个类只能继承一个直接父类(可能是抽象类),却可以实现多个接口;(接口弥补了Java的单继承)
抽象类是这个事物中应该具备的内容, 继承体系是一种 is…a关系
接口是这个事物中的额外内容,继承体系是一种 like…a关系
11-12多态概述
- 多态是继封装、继承之后,面向对象的第三大特性。
- 现实事物经常会体现出多种形态,如学生,学生是人的一种,则一个具体的同学张三既是学生也是人,即出现两种形态。
- 最终多态体现为父类引用变量可以指向子类对象。
- 在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。
11-13多态调用的三种格式
- 定义格式:
父类的引用变量指向子类对象
父类类型 变量名 = new 子类类型();
变量名.方法名();
2.例子:
public class Person {
public void name() {}
}
public class Student extends Person {
public void name() {
System.out.println("张三");
}
}
public class Test {
public static void main(String[] args) {
Person s = new Student();
s.name();
}
}
- 同一个父类的方法会被不同的子类重写。在调用方法时,调用的为各个子类重写后的方法。
- 当变量名指向不同的子类对象时,由于每个子类重写父类方法的内容不同,所以会调用不同的方法。
11-14多态成员方法的特点
/*
* 多态中,成员特点
*
* 成员变量:
* 编译的时候, 参考父类中有没有这个变量,如果有,编译成功,没有编译失败
* 运行的时候, 运行的是父类中的变量值
* 编译运行全看父类
*
* 成员方法:
* 编译的时候, 参考父类中有没有这个方法,如果有,编译成功,没有编译失败
* 运行的时候, 运行的是子类的重写方法
*
* 编译看父类,运行看子类
*/
public class Fu {
int a = 1;
public void show(){
System.out.println("父类方法");
}
}
public class Zi extends Fu{
int a = 2;
public void show(){
System.out.println("子类方法");
}
}
public class Test {
public static void main(String[] args) {
Fu f = new Zi();
System.out.println(f.a);
f.show();
}
}
11-15 instanceof关键字
- 作用:可以通过instanceof关键字来判断某个对象是否属于某种数据类型。
- 格式:
boolean b = 对象 instanceof 数据类型; - 举例:
Person p1 = new Student(); // 前提条件,学生类已经继承了人类
boolean flag = p1 instanceof Student; //flag结果为true
boolean flag2 = p2 instanceof Teacher; //flag结果为false
11-16多态-向上转型
- 多态的转型分为向上转型与向下转型两种
- 向上转型:当有子类对象赋值给一个父类引用时,便是向上转型,多态本身就是向上转型的过程。
- 使用格式:
父类类型 变量名 = new 子类类型();
如:Person p = new Student();
11-17多态-向下转型
- 向下转型:一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用转为子类引用,这个过程是向下转型。如果是直接创建父类对象,是无法向下转型的!
- 使用格式:
子类类型 变量名 = (子类类型) 父类类型的变量;
如:Student stu = (Student) p; - 向上转型的好处是隐藏了子类类型,提高了代码的扩展性。
- 向上转型也有弊端,只能使用父类共性的内容,而无法使用子类特有功能,功能有限制。
11-18多态转型的案例
//描述动物类,并抽取共性eat方法
abstract class Animal {
abstract void eat();
}
// 描述狗类,继承动物类,重写eat方法,增加lookHome方法
class Dog extends Animal {
void eat() {
System.out.println("啃骨头");
}
void lookHome() {
System.out.println("看家");
}
}
// 描述猫类,继承动物类,重写eat方法,增加catchMouse方法
class Cat extends Animal {
void eat() {
System.out.println("吃鱼");
}
void catchMouse() {
System.out.println("抓老鼠");
}
}
public class Test {
public static void main(String[] args) {
Animal a = new Dog(); //多态形式,创建一个狗对象
a.eat(); // 调用对象中的方法,会执行狗类中的eat方法
// a.lookHome();//使用Dog类特有的方法,需要向下转型,不能直接使用
// 为了使用狗类的lookHome方法,需要向下转型
// 向下转型过程中,可能会发生类型转换的错误,即ClassCastException异常
// 那么,在转之前需要做健壮性判断
if( !a instanceof Dog){ // 判断当前对象是否是Dog类型
System.out.println("类型不匹配,不能转换");
return;
}
Dog d = (Dog) a; //向下转型
d.lookHome();//调用狗类的lookHome方法
}
}
11-19笔记本电脑案例
-
A:案例介绍
* 定义USB接口(具备开启功能、关闭功能),笔记本要使用USB设备,即笔记本在生产时需要预留可以插入USB设备的USB接口,即就是笔记本具备使用USB设备的功能,
* 但具体是什么USB设备,笔记本并不关心,只要符合USB规格的设备都可以。鼠标和键盘要想能在电脑上使用,那么鼠标和键盘也必须遵守USB规范,不然鼠标和键盘的生产出来无法使用
* 进行描述笔记本类,实现笔记本使用USB鼠标、USB键盘
USB接口,包含开启功能、关闭功能
笔记本类,包含运行功能、关机功能、使用USB设备功能
鼠标类,要符合USB接口
键盘类,要符合USB接口 -
B: 案例分析
* 阶段一:
使用笔记本,笔记本有运行功能,需要笔记本对象来运行这个功能
* 阶段二:
想使用一个鼠标,又有一个功能使用鼠标,并多了一个鼠标对象。
* 阶段三:
还想使用一个键盘 ,又要多一个功能和一个对象
* 问题:每多一个功能就需要在笔记本对象中定义一个方法,不爽,程序扩展性极差。
降低鼠标、键盘等外围设备和笔记本电脑的耦合性。 -
C: 代码实现
定义鼠标、键盘,笔记本三者之间应该遵守的规则
interface USB {
void open();// 开启功能
void close();// 关闭功能
}
鼠标实现USB规则
class Mouse implements USB {
public void open() {
System.out.println("鼠标开启");
}
public void close() {
System.out.println("鼠标关闭");
}
}
键盘实现USB规则
class KeyBoard implements USB {
public void open() {
System.out.println("键盘开启");
}
public void close() {
System.out.println("键盘关闭");
}
}
定义笔记本
class NoteBook {
// 笔记本开启运行功能
public void run() {
System.out.println("笔记本运行");
}
// 笔记本使用usb设备,这时当笔记本对象调用这个功能时,必须给其传递一个符合USB规则的USB设备
public void useUSB(USB usb) {
// 判断是否有USB设备
if (usb != null) {
usb.open();
usb.close();
}
}
public void shutDown() {
System.out.println("笔记本关闭");
}
}
public class Test {
public static void main(String[] args) {
// 创建笔记本实体对象
NoteBook nb = new NoteBook();
// 笔记本开启
nb.run();
// 创建鼠标实体对象
Mouse m = new Mouse();
// 笔记本使用鼠标
nb.useUSB(m);
// 创建键盘实体对象
KeyBoard kb = new KeyBoard();
// 笔记本使用键盘
nb.useUSB(kb);
// 笔记本关闭
nb.shutDown();
}
}