#今日内容
- 接口
- 多态
##01. 接口概述与生活举例
- 结合例子, 接口是什么思想?
总结: 接口就是一种公共的规范标准
接口是对外暴露的一种规则
定义接口的人:
声明规则的
使用接口的人:
根据规则完成功能的人
##02. 接口的定义基本格式
- 接口的基本定义格式
格式: interface 接口名{}
- 接口有会产生字节码文件吗?
总结: 会的
- 接口中可以定义的内容有?
- 接口在jdk1.7的特点:
只能定义常量
抽象方法
- 接口在jdk1.8的特点:
默认方法
静态方法
- 接口在jdk1.9的特点:
私有方法
总结:
1. 常量 --> 自定义常量 -> final
2. 抽象方法 -> 必掌握
3. 默认方法 -> 了解
4. 静态方法 -> 了解
5. 私有方法 -> 了解
##03. 接口的抽象方法定义
- 接口中定义抽象方法的特点:
总结:
定义的方法即使写成 void show(); 系统也会默认加上2个关键字 public abstract
细节:
abstract关键字不能和哪些关键字共存
1. private
-> 因为被abstract修饰的方法强制要求子类重写, 而被private修饰的方法子类重写不了, 二者冲突
2. static
-> 如果允许被static修饰, 就可以通过类名点去调用没有方法体的抽象方法, 这样做没有意义.
3. final
-> 变量 方法 类
变量 : 就变成了常量, 只能被赋值一次
方法 : 不能被重写
类 : 不能被继承
-> 因为被abstract修饰的方法强制要求子类重写, 而被final修饰的方法, 子类不能重写, 二者冲突.
##04. 接口的抽象方法使用
- 思路: 接口不能实例化, 必须由实现类(子类的一种)去实现接口
- 实现接口的格式为:
总结:
class 实现类类名 implements 接口名{
}
建议:
作为接口的实现类(子类), 要么重写所有的抽象方法 --> 推荐方案
要么将自己也变成一个抽象类 -> 不推荐
步骤:
1. 定义接口 interface 接口名 { .... }
2. 找一个实现类实现这个接口-> implements class 实现类名 implements 接口名 { ... }
3. 创建实现类对象, 并调用方法
思路:
抽象类 -> 共性的内容
接口 -> 扩展的规则
##05. 接口的默认方法定义
- jdk8开始, 才可以定义默认方法
- 定义默认方法的时候, 需要加入关键字default
格式:
public default 返回值类型 方法名(){
}
- 加入默认方法, 可以解决什么样的问题?
结论: 可以解决接口的升级问题
interface A {
public abstract void methodA();
// 这里如果是一个抽象方法的话, 会影响到很多的实现类.
public default void show(){
System.out.println("我是新增加的功能show");
}
}
class AImp1 implements A {
@Override
public void methodA() {
System.out.println("AImp1....");
}
}
class AImp2 implements A{
@Override
public void methodA() {
System.out.println("AImp2....");
}
}
##06. 接口的默认方法使用
- 调用方式是?
- 实现类是否可以对默认方法进行重写?
总结:
1. 可以直接创建 实现类 的对象进行调用
2. 可以
如果实现类重写了, 那么调用的时候, 使用的就是重写之后的逻辑
如果没有重写, 使用的就是接口当中默认的逻辑
eg.
public interface Animal {
public default void method (){
System.out.println("默认方法");
}
}
public Dog implements Animal {
@Override
public void method (){ //注意重写默认方法的时候, 不能写"default"关键字.按照普通的成员方法写就行了.
System.out.println(“重写的默认方法”);
}
}
概念: 接口是一个干爹, 干爹中的数据, 实现类也是可以继承使用的.
##07. 接口的静态方法定义
- jdk1.8开始, 可以开始定义静态方法
- 格式为?
总结:
public static 返回值类型 方法名(参数列表){
方法体;
}
##08. 接口的静态方法使用
- 调用方式是?
总结:
1. 接口名称.静态方法名称();
[ 注意事项 ]静态方法无法通过实现类名或者是实现类对象进行调用.只能通过接口名.静态方法名进行调用.
interface Inter{
public static void method(){
System.out.println("1");
}
}
interface Inter2{
public static void method(){
System.out.println("2");
}
}
class InterImp implements Inter,Inter2{
}
InterImp ii = new InterImp();
ii.method(); // 错误写法
main(){
Inter.method(); // 接口名称.静态方法名称();
}
问题: 为什么接口中的静态方法, 不允许对象名调用.
特点: 接口和类之间是实现关系, 可以单实现, 也可以多实现
既然可以多实现, 就有可能, 多个接口中定义了相同的静态方法, 但是方法体不一样.
这时候就会出现冲突问题.
所以, 接口中的静态方法. 只允许接口名.进行调用, 不允许对象名调用!
##09. 接口的私有方法定义
- jdk1.9开始, 接口可以定义私有方法
- 什么情况下需要将接口中的方法进行私有?
总结:
如果一个接口中有多个默认方法,并且方法中有重复的内容,那么可以抽取出来,封装到私有方法中,供默认方法 去调用。从设计的角度讲,私有的方法是对默认方法和静态方法的辅助
换句话说:
当发现接口中的多个默认方法中, 出现了重复的代码, 我们可以将这段代码抽取到一个方法当中.
但又不希望实现类将整个逻辑性不强的方法继承使用, 就可以将该方法进行私有.
举例:
public interface MyInterfacePrivateA {
public default void methodDefault1() {
System.out.println("默认方法1");
methodCommon();
}
public default void methodDefault2() {
System.out.println("默认方法2");
methodCommon();
}
private void methodCommon() {
System.out.println("AAA");
System.out.println("BBB");
System.out.println("CCC");
}
}
##10. 接口的私有方法使用
- 代码分析
结论 : 接口中定义的私有方法, 就是解决(普通/静态)方法中, 重复代码的问题.
##11. 接口的常量定义和使用
- 接口中的变量只能是常量
总结: 因为默认加入了三个关键字 : public static final
int num = 10;
- fianl修饰变量
>* 基本数据类型
其值不能发生改变
final int a = 10;
a = 20; // 错误.
>* 引用数据类型
地址值不能发生改变, 但是可以通过setXxx方法修改属性值.
final Person p = new Person("张三",23);
p.setAge(24); // 正确
p = new Person("李四",24); // 错误
- 注意事项:
1. 接口中的常量, 必须给出初始化值.
-> final修饰的变量, 如果是成员变量的话, 初始化时机.
解释:
因为final修饰成员变量的初始化时机一共分为两种
1. 在创建成员变量的之后, 就直接赋值 --> 推荐方案
2. 在构造方法弹栈之前完成赋值
注意的是, 接口中没有构造方法, 所以能够选择的初始化时机, 就只能是在创建成员变量的时候, 直接赋值.
- 江湖规矩
定义标识符的时候, 需要见名知意, 驼峰命名
1. 变量 : 如果是一个单词, 所有字母小写 : age
如果是多个单词, 从第二个单词的首字母开始大写 : maxAge
2. 常量 : 如果是一个单词, 所有字母大写 : VALUE
如果是多个单词, 所有字母大写, 但是单词之间需要以下划线隔开 : MAX_VALUE
3. 类名 : 如果是一个单词, 首字母大写 Demo
如果是多个单词, 每个单词的首字母大写 TestFinal
4. 方法名: 如果是一个单词, 所有字母小写 : method()
如果是多个单词, 从第二个单词的首字母开始大写 : getAge();
5. 包名 : 一般都是公司的域名倒着写
itheima.com
com.itheima.xx
##12. 接口的内容小结
- 成员变量其实是常量,格式:
[public] [static] [final] 数据类型 常量名称 = 数据值;
注意:
常量必须进行赋值,而且一旦赋值不能改变。
常量名称完全大写,用下划线进行分隔。
- 接口中最重要的就是抽象方法,格式:
[public] [abstract] 返回值类型 方法名称(参数列表);
注意:实现类必须覆盖重写接口所有的抽象方法,除非实现类是抽象类。
- 从Java 8开始,接口里允许定义默认方法,格式:
[public] default 返回值类型 方法名称(参数列表) { 方法体 }
注意:默认方法也可以被覆盖重写
- 从Java 8开始,接口里允许定义静态方法,格式:
[public] static 返回值类型 方法名称(参数列表) { 方法体 }
注意:静态方法不能通过实现类的类名或者实现类的对象进行调用, 只能通过接口名.静态方法名进行调用.
- 从Java 9开始,接口里允许定义私有方法,格式:
普通私有方法:private 返回值类型 方法名称(参数列表) { 方法体 }
静态私有方法:private static 返回值类型 方法名称(参数列表) { 方法体 }
- 接口的思想(重要)
总结:
对比抽象类的思想
抽象类: 被继承体现的是一种is..a的关系, 抽象类中的行为都是共性的行为.
接口 : 接口当中定义的都是一些扩展的规则(特性的行为), 体现的是一种like..a的关系.
##13. 继承父类并实现多个接口
- 注意事项:
总结:
1.子接口重写默认方法时,default关键字可以保留。
子类重写默认方法时,default关键字不可以保留。 子父类中不能出现default关键字, 出现就是错误代码.
2.接口中,无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用public static final修饰。
3.接口中,没有构造方法,不能创建对象。
4.接口中,没有静态代码块。
- 接口的出现, 打破了java只支持单继承的局限性, 为什么?
总结: 因为接口和类之间是实现关系, 可以单实现,也可以多实现
并且可以在继承了一个类的同时, 实现多个接口
interface A{
}
interface B{
}
interface C{
}
class InterImp extends Object implements A,B,C{
}
- 接口的子类需要注意哪些?
总结:
1. 实现一个接口, 要么重写所有的抽象方法, 要么该实现类自己本身也是一个抽象类.
2. 如果实现类实现多个接口, 多个接口中存在重复的抽象方法, 实现类之重写一个即可
3. 如果实现类所实现的多个接口中, 存在重复的默认方法, 必须对冲突的默认方法重写
interface A{
public default void method(){
System.out.println("A");
}
}
interface B{
public default void method(){
System.out.println(B);
}
}
class InterImp implements A, B{
@Override
public void method(){
System.out.println("...");
}
}
4. 如果实现类, 从父类中继承下来的方法, 和接口中默认的方法重名了.
优先用父类的方法.
public class Test1_Extends {
public static void main(String[] args) {
Dog d = new Dog();
d.eat();
d.show();
}
}
class Animal{
public void eat(){
System.out.println("动物吃饭");
}
public void show(){
System.out.println("父类的show方法");
}
}
interface Inter{
void eat();
public default void show(){
System.out.println("接口中的show方法");
}
}
class Dog extends Animal implements Inter{
// 虽然和接口的抽象eat冲突, 这里使用的是父类的eat方法
public void eat(){
System.out.println("动物吃饭");
}
// 父类的show方法和接口中默认的show方法冲突, 优先使用的是父类的show方法
// d.show();
}
##14. 接口之间的多继承
- 类与类的关系:
* 继承关系, 只支持单继承, 不支持多继承, 但是可以多层继承- 类与接口的关系:
* 实现关系, 可以单实现, 也可以多实现, 并且可以在继承了一个类的同时, 实现多个接口
- 接口与接口的关系:
* 继承, 可以单继承, 也可以多继承!
interface A{
void showA();
}
interface B{
void showB();
}
interface C extends A,B{
void showC();
}
class InterImp implements C{
//重写三个抽象方法, 因为C当中继承到了showA, showB();
}
* 单独注意:
如果多个父接口当中, 出现了重复的默认方法, 那么子接口必须对方法进行覆盖重写, 而且不能省略default关键字 !!
interface A{
public defalut void show(){
System.out.println("a");
}
}
interface B{
public defalut void show(){
System.out.println("B");
}
}
interface C extends A,B{
@Override
public defalut void show(){ // defalut不能省略.
System.out.println("C");
}
}
##15. 多态的概述
- 什么是多态?
总结: 事物存在的多种形态
class Animal{
}
class Dog extends Animal{
}
main(){
Dog d = new Dog(); // 事物以狗的形态出现
Animal a = new Dog(); // 事物以动物的形态出现
}
##16. 多态的格式与使用
- 多态的前提是?
总结:
1. 要有继承关系, 实现关系
2. 要有父类引用指向子类对象. --> 多态的写法
##17. 多态中成员变量的使用特点
- 多态中成员变量的使用特点?
总结:
1. 编译看左边(父类), 运行看左边(父类)
Fu f = new Zi();
System.out.println(f.num); // 父类当中num所记录的值
细节:
编译看左边(父类), 运行看左边(父类)
因为当前是父类引用指向子类对象, 父类的引用带有局限性, 只能看到堆内存当中super的一小块区域
所以可以拿到的只能是super区域当中, 父类记录的数值.
问题: 静态成员变量呢?
静态修饰的成员跟类相关, 跟对象没有关系.
Animal a = new Dog();
System.out.println(a.abc);
此处虽然是对象名.abc, 但在编译的时候也会翻译成类名.abc
Animal.abc --> 调用静态成员, 类名是谁的, 调用的就是谁的数值.
##18. 多态中成员方法的使用特点
- 多态中成员方法的访问提点?
总结:
1. 编译看左边(父类), 运行看右边(子类)
动态绑定机制:
动态绑定:
在多态创建对象并调用成员方法的时候, 编译时会检测父类当中是否有此方法的声明
有 : 编译通过, 但是运行的时候执行子类的方法
没有 : 编译失败.
.
##19. 使用多态的好处
- 无论右边new的是那个子类对象, 左边都不会发生变化
总结:
1.
Animal a = new Dog();
Animal a = new Cat();
...
结论:
多态的出现, 提高了代码的复用性, 因为有继承保证
提高了代码的扩展性 --> 必掌握
问题: 怎么就提高了?
可以将方法的形参定义为父类类型, 该方法就可以接受这个父类的任意子类对象了.
注意: 将方法形参定义为父类类型之后, 该方法可以接受这个父类的任意子类对象, 在方法内部一般都是调用的共性内容
如果想要调用特性内容, 就需要向下转型, 莫不如直接创建子类对象.
##20. 对象的向上转型
- 什么是多态的向上转型?
总结:
1. Animal a = new Dog(); // 父类引用指向子类对象
对比:
double d = 10;
##21. 对象的向下转型
- 为什么要向下转型?
总结:
多态的弊端: 不能调用子类特有的属性和行为.
如果非要调用子类特有的功能, 就必须向下转型.
向下转型的举例:
超人的例子.
注意: 向下转型的强转必须发生在子父类的关系内, 而且必须是转上去, 才能转下来.
什么情况下需要用到向下转型?
答: 为了调用子类特有的属性和行为.
ClassCastException(类型转换异常): 引用数据类型的强转, 出现了错误.
例如:
1. Animal a = new Cat();
Dog d = (Dog)a; --> Cat和Dog之间没有子父类关系, 不能强转
2. Animal a = new Animal();
Dog d = (Dog) a; --> 必须要先进行向上转型, 才可以将数据正常的转型下来.
##22. 用instanceof关键字进行类型判断
- instanceof关键字的作用是什么?
总结:
1. 判断左边的引用, 是否是右边的数据类型.
public static void useAnimal(Animal a){ // Animal a = new Cat();
a.eat();
if(a instanceof Dog){
Dog d = (Dog) a;
d.lookHome();
}else if (a instanceof Cat){
Cat c = (Cat) a;
c.catchMouse();
}
}
多态的好处:
多态可以提高代码的扩展性, 可以将方法的形参定义为父类类型, 该方法就能接收这个父类的任意子类对象.
方法内部一般只调用该体系当中共性的内容, 如果要调用特性的, 干脆就创建子类对象.
##23. 笔记本USB接口案例_分析
- 看图说话
##24. 笔记本USB接口案例_实现
- 示例代码
总结:
1.