今日内容

  • 接口
  • 多态

01. 接口概述与生活举例

  • 结合例子, 接口是什么思想?
  1. 总结: 接口就是一种公共的规范标准
  2. 接口是对外暴露的一种规则
  3. 定义接口的人:
  4. 声明规则的
  5. 使用接口的人:
  6. 根据规则完成功能的人

02. 接口的定义基本格式

  • 接口的基本定义格式
  1. 格式: interface 接口名{}
  • 接口有会产生字节码文件吗?
  1. 总结: 会的
  • 接口中可以定义的内容有?
  • 接口在jdk1.7的特点:
  1. 只能定义常量
  2. 抽象方法
  • 接口在jdk1.8的特点:
  1. 默认方法
  2. 静态方法
  • 接口在jdk1.9的特点:
  1. 私有方法
  2. 总结:
  3. 1. 常量 --> 自定义常量 -> final
  4. 2. 抽象方法 -> 必掌握
  5. 3. 默认方法 -> 了解
  6. 4. 静态方法 -> 了解
  7. 5. 私有方法 -> 了解

03. 接口的抽象方法定义

  • 接口中定义抽象方法的特点:
  1. 总结:
  2. 定义的方法即使写成 void show(); 系统也会默认加上2个关键字 public abstract
  3. 细节:
  4. abstract关键字不能和哪些关键字共存
  5. 1. private
  6. -> 因为被abstract修饰的方法强制要求子类重写, 而被private修饰的方法子类重写不了, 二者冲突
  7. 2. static
  8. -> 如果允许被static修饰, 就可以通过类名点去调用没有方法体的抽象方法, 这样做没有意义.
  9. 3. final
  10. -> 变量 方法
  11. 变量 : 就变成了常量, 只能被赋值一次
  12. 方法 : 不能被重写
  13. : 不能被继承
  14. -> 因为被abstract修饰的方法强制要求子类重写, 而被final修饰的方法, 子类不能重写, 二者冲突.

04. 接口的抽象方法使用

  • 思路: 接口不能实例化, 必须由实现类(子类的一种)去实现接口
  • 实现接口的格式为:
  1. 总结:
  2. class 实现类类名 implements 接口名{
  3. }
  4. 建议:
  5. 作为接口的实现类(子类), 要么重写所有的抽象方法 --> 推荐方案
  6. 要么将自己也变成一个抽象类 -> 不推荐
  7. 步骤:
  8. 1. 定义接口 interface 接口名 { .... }
  9. 2. 找一个实现类实现这个接口-> implements class 实现类名 implements 接口名 { ... }
  10. 3. 创建实现类对象, 并调用方法
  11. 思路:
  12. 抽象类 -> 共性的内容
  13. 接口 -> 扩展的规则

05. 接口的默认方法定义

  • jdk8开始, 才可以定义默认方法
  • 定义默认方法的时候, 需要加入关键字default
  1. 格式:
  2. public default 返回值类型 方法名(){
  3. }
  • 加入默认方法, 可以解决什么样的问题?
  1. 结论: 可以解决接口的升级问题
  2. interface A {
  3. public abstract void methodA();
  4. // 这里如果是一个抽象方法的话, 会影响到很多的实现类.
  5. public default void show(){
  6. System.out.println("我是新增加的功能show");
  7. }
  8. }
  9. class AImp1 implements A {
  10. @Override
  11. public void methodA() {
  12. System.out.println("AImp1....");
  13. }
  14. }
  15. class AImp2 implements A{
  16. @Override
  17. public void methodA() {
  18. System.out.println("AImp2....");
  19. }
  20. }

06. 接口的默认方法使用

  • 调用方式是?
  • 实现类是否可以对默认方法进行重写?
  1. 总结:
  2. 1. 可以直接创建 实现类 的对象进行调用
  3. 2. 可以
  4. 如果实现类重写了, 那么调用的时候, 使用的就是重写之后的逻辑
  5. 如果没有重写, 使用的就是接口当中默认的逻辑
  1. eg.
  2. public interface Animal {<br /> public default void method (){<br /> System.out.println("默认方法");<br /> }<br /> }
  3. public Dog implements Animal {<br /> [@Override ]()<br /> public void method (){ //注意重写默认方法的时候, 不能写"default"关键字.按照普通的成员方法写就行了.<br /> System.out.println("重写的默认方法");<br /> }<br /> }
  1. 概念: 接口是一个干爹, 干爹中的数据, 实现类也是可以继承使用的.

07. 接口的静态方法定义

  • jdk1.8开始, 可以开始定义静态方法
  • 格式为?
  1. 总结:
  2. public static 返回值类型 方法名(参数列表){
  3. 方法体;
  4. }

08. 接口的静态方法使用

  • 调用方式是?
  1. 总结:
  2. 1. 接口名称.静态方法名称();
  3. [ 注意事项 ]静态方法无法通过实现类名或者是实现类对象进行调用.只能通过接口名.静态方法名进行调用.
  4. interface Inter{
  5. public static void method(){
  6. System.out.println("1");
  7. }
  8. }
  9. interface Inter2{
  10. public static void method(){
  11. System.out.println("2");
  12. }
  13. }
  1. class InterImp implements Inter,Inter2{
  2. }
  1. InterImp ii = new InterImp();
  2. ii.method(); // 错误写法
  1. main(){<br /> Inter.method(); // 接口名称.静态方法名称();<br /> }
  2. 问题: 为什么接口中的静态方法, 不允许对象名调用.
  3. 特点: 接口和类之间是实现关系, 可以单实现, 也可以多实现
  1. 既然可以多实现, 就有可能, 多个接口中定义了相同的静态方法, 但是方法体不一样.
  2. 这时候就会出现冲突问题.
  3. 所以, 接口中的静态方法. 只允许接口名.进行调用, 不允许对象名调用!

09. 接口的私有方法定义

  • jdk1.9开始, 接口可以定义私有方法
  • 什么情况下需要将接口中的方法进行私有?
  1. 总结:
  2. 如果一个接口中有多个默认方法,并且方法中有重复的内容,那么可以抽取出来,封装到私有方法中,供默认方法 去调用。从设计的角度讲,私有的方法是对默认方法和静态方法的辅助
  3. 换句话说:
  4. 当发现接口中的多个默认方法中, 出现了重复的代码, 我们可以将这段代码抽取到一个方法当中.
  5. 但又不希望实现类将整个逻辑性不强的方法继承使用, 就可以将该方法进行私有.
  6. 举例:
  7. public interface MyInterfacePrivateA {
  8. public default void methodDefault1() {
  9. System.out.println("默认方法1");
  10. methodCommon();
  11. }
  12. public default void methodDefault2() {
  13. System.out.println("默认方法2");
  14. methodCommon();
  15. }
  16. private void methodCommon() {
  17. System.out.println("AAA");
  18. System.out.println("BBB");
  19. System.out.println("CCC");
  20. }
  21. }

10. 接口的私有方法使用

  • 代码分析
  1. 结论 : 接口中定义的私有方法, 就是解决(普通/静态)方法中, 重复代码的问题.

11. 接口的常量定义和使用

  • 接口中的变量只能是常量
  1. 总结: 因为默认加入了三个关键字 : public static final
  2. int num = 10;
  • fianl修饰变量
  1. >* 基本数据类型
  2. 其值不能发生改变
  3. final int a = 10;
  4. a = 20; // 错误.
  5. >* 引用数据类型
  6. 地址值不能发生改变, 但是可以通过setXxx方法修改属性值.
  7. final Person p = new Person("张三",23);
  8. p.setAge(24); // 正确
  9. p = new Person("李四",24); // 错误
  • 注意事项:
  1. 1. 接口中的常量, 必须给出初始化值.
  2. -> final修饰的变量, 如果是成员变量的话, 初始化时机.
  1. 解释:
  2. 因为final修饰成员变量的初始化时机一共分为两种<br /> 1. 在创建成员变量的之后, 就直接赋值 --> 推荐方案<br /> 2. 在构造方法弹栈之前完成赋值
  3. 注意的是, 接口中没有构造方法, 所以能够选择的初始化时机, 就只能是在创建成员变量的时候, 直接赋值.
  • 江湖规矩
  1. 定义标识符的时候, 需要见名知意, 驼峰命名
  2. 1. 变量 : 如果是一个单词, 所有字母小写 : age
  3. 如果是多个单词, 从第二个单词的首字母开始大写 : maxAge
  4. 2. 常量 : 如果是一个单词, 所有字母大写 : VALUE
  5. 如果是多个单词, 所有字母大写, 但是单词之间需要以下划线隔开 : MAX_VALUE
  6. 3. 类名 : 如果是一个单词, 首字母大写 Demo
  7. 如果是多个单词, 每个单词的首字母大写 TestFinal
  8. 4. 方法名: 如果是一个单词, 所有字母小写 : method()
  9. 如果是多个单词, 从第二个单词的首字母开始大写 : getAge();
  10. 5. 包名 : 一般都是公司的域名倒着写
  11. itheima.com
  12. com.itheima.xx

12. 接口的内容小结

  • 在Java 9+版本中,接口的内容可以有:

    1. 成员变量其实是常量,格式:
  1. [public] [static] [final] 数据类型 常量名称 = 数据值;
  2. 注意:
  3. 常量必须进行赋值,而且一旦赋值不能改变。
  4. 常量名称完全大写,用下划线进行分隔。

    1. 接口中最重要的就是抽象方法,格式:
  1. [public] [abstract] 返回值类型 方法名称(参数列表);
  2. 注意:实现类必须覆盖重写接口所有的抽象方法,除非实现类是抽象类。

    1. 从Java 8开始,接口里允许定义默认方法,格式:
  1. [public] default 返回值类型 方法名称(参数列表) { 方法体 }
  2. 注意:默认方法也可以被覆盖重写

    1. 从Java 8开始,接口里允许定义静态方法,格式:
  1. [public] static 返回值类型 方法名称(参数列表) { 方法体 }
  2. 注意:静态方法不能通过实现类的类名或者实现类的对象进行调用, 只能通过接口名.静态方法名进行调用.

    1. 从Java 9开始,接口里允许定义私有方法,格式:
  1. 普通私有方法:private 返回值类型 方法名称(参数列表) { 方法体 }
  2. 静态私有方法:private static 返回值类型 方法名称(参数列表) { 方法体 }
  • 接口的思想(重要)
  1. 总结:
  2. 对比抽象类的思想
  3. 抽象类: 被继承体现的是一种is..a的关系, 抽象类中的行为都是共性的行为.
  4. 接口 : 接口当中定义的都是一些扩展的规则(特性的行为), 体现的是一种like..a的关系.

13. 继承父类并实现多个接口

  • 注意事项:
  1. 总结:
  2. 1.子接口重写默认方法时,default关键字可以保留。
  3. 子类重写默认方法时,default关键字不可以保留。 子父类中不能出现default关键字, 出现就是错误代码.
  4. 2.接口中,无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用public static nal修饰。
  5. 3.接口中,没有构造方法,不能创建对象。
  6. 4.接口中,没有静态代码块。
  • 接口的出现, 打破了java只支持单继承的局限性, 为什么?
  1. 总结: 因为接口和类之间是实现关系, 可以单实现,也可以多实现
  2. 并且可以在继承了一个类的同时, 实现多个接口
  3. interface A{
  4. }
  5. interface B{
  6. }
  7. interface C{
  8. }
  9. class InterImp extends Object implements A,B,C{
  1. }
  • 接口的子类需要注意哪些?
  1. 总结:
  2. 1. 实现一个接口, 要么重写所有的抽象方法, 要么该实现类自己本身也是一个抽象类.
  3. 2. 如果实现类实现多个接口, 多个接口中存在重复的抽象方法, 实现类之重写一个即可
  4. 3. 如果实现类所实现的多个接口中, 存在重复的默认方法, 必须对冲突的默认方法重写
  5. interface A{
  6. public default void method(){
  7. System.out.println("A");
  8. }
  9. }
  10. interface B{
  11. public default void method(){
  12. System.out.println(B);
  13. }
  14. }
  15. class InterImp implements A, B{
  16. @Override
  17. public void method(){
  18. System.out.println("...");
  19. }
  20. }
  21. 4. 如果实现类, 从父类中继承下来的方法, 和接口中默认的方法重名了.
  22. 优先用父类的方法.
  1. public class Test1_Extends {<br /> public static void main(String[] args) {<br /> Dog d = new Dog();<br /> d.eat();<br /> d.show();<br /> }<br /> }
  2. class Animal{<br /> public void eat(){<br /> System.out.println("动物吃饭");<br /> }
  3. public void show(){<br /> System.out.println("父类的show方法");<br /> }<br /> }
  1. interface Inter{
  2. void eat();
  3. public default void show(){
  4. System.out.println("接口中的show方法");
  5. }
  6. }
  7. class Dog extends Animal implements Inter{
  8. // 虽然和接口的抽象eat冲突, 这里使用的是父类的eat方法
  9. public void eat(){
  10. System.out.println("动物吃饭");
  11. }
  12. // 父类的show方法和接口中默认的show方法冲突, 优先使用的是父类的show方法
  13. // d.show();
  14. }

14. 接口之间的多继承

  • 类与类的关系:
  • 继承关系, 只支持单继承, 不支持多继承, 但是可以多层继承
  • 类与接口的关系:
  • 实现关系, 可以单实现, 也可以多实现, 并且可以在继承了一个类的同时, 实现多个接口
  • 接口与接口的关系:
  • 继承, 可以单继承, 也可以多继承!
  1. interface A{
  2. void showA();
  3. }
  4. interface B{
  5. void showB();
  6. }
  7. interface C extends A,B{
  8. void showC();
  9. }
  10. class InterImp implements C{
  11. //重写三个抽象方法, 因为C当中继承到了showA, showB();
  12. }
  13. * 单独注意:
  14. 如果多个父接口当中, 出现了重复的默认方法, 那么子接口必须对方法进行覆盖重写, 而且不能省略default关键字 !!
  15. interface A{
  16. public defalut void show(){
  17. System.out.println("a");
  18. }
  19. }
  20. interface B{
  21. public defalut void show(){
  22. System.out.println("B");
  23. }
  24. }
  25. interface C extends A,B{
  26. @Override
  27. public defalut void show(){ // defalut不能省略.
  28. System.out.println("C");
  29. }
  30. }

15. 多态的概述

  • 什么是多态?
  1. 总结: 事物存在的多种形态
  2. class Animal{
  3. }
  4. class Dog extends Animal{
  5. }
  6. main(){
  7. Dog d = new Dog(); // 事物以狗的形态出现
  8. Animal a = new Dog(); // 事物以动物的形态出现
  9. }

16. 多态的格式与使用

  • 多态的前提是?
  1. 总结:
  2. 1. 要有继承关系, 实现关系
  3. 2. 要有父类引用指向子类对象. --> 多态的写法

17. 多态中成员变量的使用特点

  • 多态中成员变量的使用特点?
  1. 总结:
  2. 1. 编译看左边(父类), 运行看左边(父类)
  3. Fu f = new Zi();
  4. System.out.println(f.num); // 父类当中num所记录的值
  5. 细节:
  6. 编译看左边(父类), 运行看左边(父类)
  7. 因为当前是父类引用指向子类对象, 父类的引用带有局限性, 只能看到堆内存当中super的一小块区域
  8. 所以可以拿到的只能是super区域当中, 父类记录的数值.
  9. 问题: 静态成员变量呢?
  10. 静态修饰的成员跟类相关, 跟对象没有关系.
  11. Animal a = new Dog();
  12. System.out.println(a.abc);
  13. 此处虽然是对象名.abc, 但在编译的时候也会翻译成类名.abc
  14. Animal.abc --> 调用静态成员, 类名是谁的, 调用的就是谁的数值.

18. 多态中成员方法的使用特点

  • 多态中成员方法的访问提点?
  1. 总结:
  2. 1. 编译看左边(父类), 运行看右边(子类)
  3. 动态绑定机制:
  4. 动态绑定:
  5. 在多态创建对象并调用成员方法的时候, 编译时会检测父类当中是否有此方法的声明
  6. : 编译通过, 但是运行的时候执行子类的方法
  7. 没有 : 编译失败.
  8. .

19. 使用多态的好处

  • 无论右边new的是那个子类对象, 左边都不会发生变化
  1. 总结:
  2. 1.
  3. Animal a = new Dog();
  4. Animal a = new Cat();
  5. ...
  6. 结论:
  7. 多态的出现, 提高了代码的复用性, 因为有继承保证
  8. 提高了代码的扩展性 --> 必掌握
  9. 问题: 怎么就提高了?
  10. 可以将方法的形参定义为父类类型, 该方法就可以接受这个父类的任意子类对象了.
  11. 注意: 将方法形参定义为父类类型之后, 该方法可以接受这个父类的任意子类对象, 在方法内部一般都是调用的共性内容
  12. 如果想要调用特性内容, 就需要向下转型, 莫不如直接创建子类对象.

20. 对象的向上转型

  • 什么是多态的向上转型?
  1. 总结:
  2. 1. Animal a = new Dog(); // 父类引用指向子类对象
  3. 对比:
  4. double d = 10;

21. 对象的向下转型

  • 为什么要向下转型?
  1. 总结:
  2. 多态的弊端: 不能调用子类特有的属性和行为.
  3. 如果非要调用子类特有的功能, 就必须向下转型.
  4. 向下转型的举例:
  5. 超人的例子.
  1. 注意: 向下转型的强转必须发生在子父类的关系内, 而且必须是转上去, 才能转下来.
  2. 什么情况下需要用到向下转型?<br /> 答: 为了调用子类特有的属性和行为.
  3. ClassCastException(类型转换异常): 引用数据类型的强转, 出现了错误.

例如:

  1. 1. Animal a = new Cat();
  2. Dog d = (Dog)a; --> CatDog之间没有子父类关系, 不能强转
  3. 2. Animal a = new Animal();
  4. Dog d = (Dog) a; --> 必须要先进行向上转型, 才可以将数据正常的转型下来.

22. 用instanceof关键字进行类型判断

  • instanceof关键字的作用是什么?
  1. 总结:
  2. 1. 判断左边的引用, 是否是右边的数据类型.
  1. public static void useAnimal(Animal a){ // Animal a = new Cat();<br /> a.eat();
  2. if(a instanceof Dog){<br /> Dog d = (Dog) a;<br /> d.lookHome();<br /> }else if (a instanceof Cat){<br /> Cat c = (Cat) a;<br /> c.catchMouse();<br /> }<br /> }
  1. 多态的好处:
  2. 多态可以提高代码的扩展性, 可以将方法的形参定义为父类类型, 该方法就能接收这个父类的任意子类对象.
  3. 方法内部一般只调用该体系当中共性的内容, 如果要调用特性的, 干脆就创建子类对象.

23. 笔记本USB接口案例_分析

  • 看图说话

24. 笔记本USB接口案例_实现

  • 示例代码
  1. 总结:
  2. 1.