day_3【接口、多态】
文章内容:
案例实现:
第一章 接口:
1.2 定义格式:
public interface 接口名称 {// 抽象方法// 默认方法// 静态方法// 私有方法}
接口概述与生活举例:
接口就是一种公共的规范标准!
只要符合规范标准,就可以大家通用!
接口的定义基本格式!:
接口就是多个类的公共规范
接口是一种引用数据类型,最重要的内容就是其中的:抽象方法
如何定义一个接口的格式:
public interface 接口名称{
接口内容 }
备注:换成了关键字interface之后,编译生成的字节码文件仍然是:.java --> .class
如果是java7,那么接口中可以包含的内容有:
1.常量 2.抽象方法
如果是java8,还可以额外包含有:3.默认方法4.静态方法
如果是java9,还可以额外包含有:5.私有方法
接口使用步骤:
1.接口不能直接使用,必须有一个“实现类”来“实现”该接口
格式:public class 实现类名称 implements 接口名称{
JAVA的版本越高级,内容就越齐全!
接口的抽象方法定义:
在任何版本的JAVA中,接口都能定义抽象方法
格式:
public interface 返回值类型 方法名称(参数列表);
注意事项:
1.接口当中的抽象方法,修饰符必须是两个固定的关键字:public abstract
2.这两个关键字修饰符,可以选择性的省略(刚学习,不推荐)
方法的三要素,可以随意定义
public interface App{
//这是一个抽象方法!
public abstract void APK();
//这也是一个抽象方法!
abstract void APK1();
//这就是抽象方法!
void APK2();
}
接口的静态方法定义
接口使用步骤:
1.接口不能直接使用,必须有一个“实现类”来“实现”该接口。
格式:public class 实现类名称 implements 接口名称 {
}
2.接口的实现类必须覆盖重写(实现)接口中所有的抽象方法。
实现:去掉abstract关键字,加上方法体大括号。
3创建实现类的对象,进行使用。
注意事项:
如果实现类并没有覆盖重写接口中所有的抽象方法,那么这个实现类自己就必须是抽象类。
从java 8开始,接口中允许定义默认方法。
格式:public default 返回值类型 方法名称(参数列表) {
方法体
}备注:接口房中的默认方法,可以解决接口升级的问题。
从JAVA8 开始,接口中允许定义静态方法。格式:
public static 返回值类型 方法名称(参数列表) {
方法体
}
提示:就是将abstract或者default换成static即可,带上方法体。
*/
public interface MyInterfaceDefault {
// 抽象方法
public abstract void methodAbs();
// 新添加了一个抽象方法
// public abstract void methodAbs2();
// 新添加的方法,改成默认方法
public default void methodDefault() {
System.out.println("这是新添加的默认方法");
}
}
* 注意事项:不能通过接口实现类的对象来调用接口当中的静态方法。
* 正确用法:通过接口名称,直接调用其中的静态方法。
* 格式: 接口名称.静态方法名(参数);
* 注意事项:不能通过接口实现类的对象来调用接口当中的静态方法。
* 正确用法:通过接口名称,直接调用其中的静态方法。
* 格式:
* 接口名称.静态方法名(参数);
public class Demo03Interface {
public static void main(String[] args) {
// 创建了实现类对象
MyInterfaceStaticImpl impl = new MyInterfaceStaticImpl();
// 错误写法!
// impl.methodStatic();
// 直接通过接口名称调用静态方法
MyInterfaceStatic.methodStatic();
}
}
接口的私有方法使用!
问题描述:
我们需要抽取一个共有方法,用来解决两个默认方法之间重复代码的问题。
但是这个共有方法不应该让实现类使用,应该是私有化的。
解决方案:从JAVA 9 开始,接口当中允许定义私有方法。
1. 普通私有方法,解决多个默认方法之间重复代码问题
格式: private 返回值类型 方法名称(参数列表) {
方法体 }2. 静态私有方法,解决多个静态方法之间重复代码问题
格式: private static 返回值类型 方法名称(参数列表) {
方法体
}
public interface aip {
public default void methodDefault1() {
System.out.println("默认方法1");
methodCommon();
}
}
接口内容常量定义和使用
接口当中也可以定义“成员变量”,但是必须使用public static final三个关键字进行修饰。
从效果上看,这其实就是接口的【常量】。格式:public static final 数据类型 常量名称 = 数据值;
注意
一旦使用final关键字进行修饰,说明不可改变。
备注:
1.接口当中的常量,可以省略public static final,注意:不写也照样是这样。
2.接口当中的常量,必须进行赋值;不能不赋值。
3.接口中常量的名称,使用完全大写的字母,用下划线进行分隔。(推荐命名规则)
public interface aip {
//这就是一个常量,一旦赋值,不可修改
public static final int NUM_OF_MY_CLASS = 12;
}
接口类总结!
在JAVA 9+ 版本中,接口的内容可以有:
1.成员变量其实是常量 格式:
[public] [static] [final] 数据类型 常量名称 = 数据值;
注意:1.常量必须进行赋值,而且一旦赋值不能改变。
2.常量名称完全大写,用下划线来进行分割.
2.接口中最重要的就是抽象方法,格式:
[public] [abstract] 返回值类型 方法名称(参数列表);
注意:实现类必须覆盖重写接口所以的抽象方法,除非实现类是抽象类 (这里可以使用@Override来检查是否有覆盖)
3.从JAVA8开始 接口里允许定义默认方法:格式
[public] default 返回值类型 方法名称(参数列表) {方法体}
注意:默认方法也可以被覆盖重写
4.从JAVA8开始 ,接口里面允许定义静态方法 格式:
[public] static 返回值类型 方法名称(参数列表) {方法体}
注意:应该通过接口名称进行调用,不能通过实现类对象调用接口静态方法
5. 从JAVA9开始 ,接口里允许定义私有很乏 格式:
普通私有方法:private 返回值类型 方法名称(参数列表) {方法体}
静态私有方法:private static 返回值类型 方法名称(参数列表){方法体}
注意:private 的方法只有接口自己才能调用,不能被实现类或者别人使用!
继承父类并实现多个接口
使用接口的时候,需要注意:
1.接口是没有静态代码块或者构造方法的。
2.一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。
格式:public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
覆盖重写所有抽象方法
3.如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
4.如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类必须是一个抽象类。
5.如果实现类所实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
6.一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先使用父类当中的方法。
接口之间的多继承
1.类与类之间是多继承的,直接父类只有一个。
2.类与接口之间是多实现的,一个类可以实现多个接口。
3.接口与接口之间是多继承的
注意事项:
1.多个父接口当中的抽象方法如果重复,没关系。
2.多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写[而且带着default
关键字]。
面向对象的三大特征之一:多态的概述
面向对象三大特征:封装性,继承性,多态性。extends继承或者implements实现,是多态性的前提。
多态的格式与使用
* 代码当中体现多态性,其实就是一句话:父类引用指向子类对象。
* 格式:
* 父类名称 对象名 = new 子类名称();
* 或者: (左父右子)
* 接口名称 对象名 = new 实现类名称();
public class aip {
public static void main(String[] arg){
//使用多态的写法
//左则是父类的引用,右则是子类的对象
FU obj = new ZI();
obj.method();
obj.methodZI();
}
}
多态中成员变量的使用特点!
在多态的代码中,成员方法的访问规则是:
看new的是谁,就优先用谁,没有则向上找
口诀:编译看左边,运行看右边
对比一下:
成员变量:编译看左边,运行还看左边
成员方法:编译看左边,运行看右边
使用的多态性的特点
如果不用多态,只用子类,那么写法是:
Teacher one = new teacher();
One.work() ://讲课
Assistant two = new Assistant()
Two.work();//辅导
我现在唯一要做的事情,就是要调用work方法,其他的功能不关心
如果使用多态的写法,对比一下:
Employee one = new Teacher();
One .work () //讲课
Employee two = new Assistant();
Two.work();//辅导
好处:无论右边NEW的时候换成那个子类对象,等号左边调用方法都不会变化!
对象的向上转型
对象的向上转型!
格式:父类名称 对象名 = New 子类名称();
Animal animal = new Cat();
含义:右侧创建一个子类对象,把它当作父类来看待使用
创建一只猫,当作动物看待,没问题。
注意事项:向上转型一定是安全的,从小范围转向了大范围,向上转换成为了更大范围的动物。
类似于:
double num =100 ;//正确
int --> double 自动类型转换!
对象的向上转型,就是父类引用指向之类对象!!(左父右子)
对象的向下转型
向下转型一定是安全的,没有问题的,正确的,但是也有一个弊端!
对象一旦向上转型为父类,那么就无法调用子类原本特有的内容
解决方案:用对象的向下转型【还原】。
对象的向下转型,其实是一个【还原】的动作
格式:子类名称 对象名 = (子类名称)父类对象:
含义:将父类对象,【还原】成为本来的子类对象!
Animal animal =new Cat(); //本来是猫,向上转型成为动物。
Cat cat =(Cat) animal ; //本来是猫,已经被当做动物了,还原回来成为本来的猫
注意事项:
1.必须保证对象本来创建的时候,就是猫,才能向下转型成为猫
2.如果对象创建的时候本来不是猫,就是会报错!
类似于:int num = (int) 10.0 //可以
int num = (int) 10.5 //不可以,精度损失
这里就有一个问题了:我拿到了一个父类的引用我怎么知道他是猫还狗呢?
用instanceof关键字进行类型判断
如何才知道一个类是否为抽象类呢?
格式:abstractclass类名称 对象instanceof类名称
这将会得到一个boolean值结果,也就是判断前面的对象能不能当做后面类型的实例
向下转型一定要使用intstanceof进行一个检查,这样才不容易报错!
接口多态的综合案例
笔记本电脑(laptop)
通常具备使用USB设备的功能。在生产时,笔记本都预留了可以插入USB设备的USB接口, 但具体是什么USB设备,笔记本厂商并不关心,只要符合USB规格的设备都可以。定义USB接口,具备最基本的开启功能和关闭功能。鼠标和键盘要想能在电脑上使用,那么鼠标和键盘也必须遵守 USB规范,实现USB接口,否则鼠标和键盘的生产出来也无法使用。
案例分析
进行描述笔记本类,实现笔记本使用 USB 鼠标、 USB 键盘USB 接口,包含开启功能、关闭功能笔记本类,包含运行功能、关机功能、使用 USB 设备功能鼠标类,要实现 USB 接口,并具备点击的方法键盘类,要实现 USB 接口,具备敲击的方法
案例实现:
定义USB接口:
interface USB {void open (); // 开启功能void close (); // 关闭功能}
定义鼠标类:
class Mouse implements USB {public void open () {System . out . println ( " 鼠标开启,红灯闪一闪 " );}public void close () {System . out . println ( " 鼠标关闭,红灯熄灭 " );}public void click (){System . out . println ( " 鼠标单击 " );}}
class KeyBoard implements USB {public void open () {System . out . println ( " 键盘开启,绿灯闪一闪 " );}public void close () {System . out . println ( " 键盘关闭,绿灯熄灭 " );}public void type (){System . out . println ( " 键盘打字 " );}}
定义笔记本类:class Laptop {// 笔记本开启运行功能public void run () {System . out . println ( " 笔记本运行 " );}// 笔记本使用 usb 设备,这时当笔记本对象调用这个功能时,必须给其传递一个符合 USB 规则的 USB 设备public void useUSB ( USB usb ) {// 判断是否有 USB 设备if ( usb != null ) {usb . open ();// 类型转换 , 调用特有方法if ( usb instanceof Mouse ){Mouse m = (Mouse ) usb ;m . click ();} else if ( usb instanceof KeyBoard ){KeyBoard kb = ( KeyBoard ) usb ;kb . type ();}usb . close ();}}public void shutDown () {System . out . println ( " 笔记本关闭 " );}}