在继承体系中,一个类只能继承一个父类。而对于接口而言,一个类是可以实现多个接口的,这叫做接口的多实现。并且,一个类能继承一个父类,同时实现多个接口。
注意事项:
使用接口的时候,需要注意:
- 接口是没有静态代码块或者构造方法的。
- 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口。
格式:
public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
// 覆盖重写所有抽象方法
} - 如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需要覆盖重写一次即可。
- 如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类就必须是一个抽象类。
- 如果实现类实现的多个接口当中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
- 一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法。
实战:
接口A
package cn.itcast.day10.demo02;
public interface MyInterfaceA {
// 错误写法!接口中不能有静态代码块
// static{
//
// }
// 错误写法!接口中不能有构造方法
// public MyInterfaceA(){}
public abstract void methodA();
public abstract void methodAbs();
public default void methodDefault(){
System.out.println("默认方法AAA");
}
}
接口B
package cn.itcast.day10.demo02;
public interface MyInterfaceB {
// 错误写法!接口不能有静态代码块
// static {
//
// }
// 错误写法!接口不能有构造方法
// public MyInterfaceA(){
//
// }
public abstract void methodB();
public abstract void methodAbs();
public default void methodDefault(){
System.out.println("默认方法BBB");
}
}
实现类实现接口A,B; 没有覆盖重写接口A,B中所有的抽象方法,因此该类必须是抽象类
package cn.itcast.day10.demo02;
public abstract class MyInterfaceAbstract implements MyInterfaceA, MyInterfaceB{
@Override
public void methodA() {
}
// @Override
// public void methodB() {
//
// }
@Override
public void methodAbs() {
}
@Override
public void methodDefault(){
}
}
实现类覆盖重写了A,B接口中的所有抽象方法,并对冲突的默认方法进行了覆盖重写
package cn.itcast.day10.demo02;
public class MyInterfaceImpl /*extends Object*/ implements MyInterfaceA, MyInterfaceB{
@Override
public void methodA() {
System.out.println("覆盖重写了A方法");
}
@Override
public void methodB() {
System.out.println("覆盖重写了B方法");
}
@Override
public void methodAbs() {
System.out.println("覆盖重写了AB接口中都有的抽象方法");
}
@Override
public void methodDefault(){
System.out.println("对多个接口当中冲突的默认方法进行覆盖重写");
}
}
一个类如果直接父类当中的方法,和接口当中的默认方法产生了冲突,优先用父类当中的方法。
父类:
package cn.itcast.day10.demo02;
public class Fu {
public void method(){
System.out.println("父类方法");
}
}
接口:
package cn.itcast.day10.demo02;
public interface MyInterface {
public default void method(){
System.out.println("接口的默认方法");
}
}
实现类,继承父类方法并且实现接口
package cn.itcast.day10.demo02;
public class Demo01Interface {
public static void main(String[] args) {
Zi zi = new Zi();
zi.method();
}
}
结果如下所示:
- 类与类之间是单继承的。直接父类只有一个。
- 类与接口之间是多实现的。一个类可以实现多个接口。
3. 接口与接口之间是多继承的。
注意事项:
- 多个父接口当中的抽象方法如果重复,没关系。
2. 多个父接口当中的默认方法如果重复,那么子接口必须进行默认方法的覆盖重写,【而且带着default关键字】。
父类接口A
package cn.itcast.day10.demo03;
public interface MyInterfaceA {
public abstract void methodA();
public abstract void methodCommon();
public default void methodDefault(){
System.out.println("AAA");
}
}
父类接口B
package cn.itcast.day10.demo03;
public interface MyInterfaceB {
public abstract void methodB();
public abstract void methodCommon();
public default void methodDefault(){
System.out.println("BBB");
}
}
子接口继承接口A,B
package cn.itcast.day10.demo03;
public interface MyInterface extends MyInterfaceA, MyInterfaceB{
public abstract void method();
@Override
public default void methodDefault(){
}
}
接口中的多态性
代码当中体现多态性,其实就是一句话:父类引用指向子类对象。
格式:
父类名称 对象名 = new 子类名称();
或者:
接口名称 对象名 = new 实现类名称();
下面介绍类中的多态性:
父类:
package cn.itcast.day10.demo04;
public class Fu {
public void method(){
System.out.println("父类方法");
}
public void methodFu(){
System.out.println("父类特有方法");
}
}
子类方法
package cn.itcast.day10.demo04;
public class Zi extends Fu{
@Override
public void method(){
System.out.println("子类方法");
}
}
main方法
package cn.itcast.day10.demo04;
public class Demo01Multi {
public static void main(String[] args) {
// 使用多态的写法
// 左侧父类的引用,指向了右侧子类的对象
Fu obj = new Zi();
obj.method();
obj.methodFu();
}
}
运行结果:
多态中成员变量的访问规则:
访问成员变量的两种方式:
- 直接通过对象名称访问成员变量:看等号左边是谁,优先用谁,没有则向上找。
- 间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找。
在多态的代码当中,成员方法的访问规则是:
看new的是谁,就优先用谁,没有则向上找。
口诀:编译看左边,运行看右边。
对比一下:
成员变量:编译看左边,运行还看左边。
成员方法:编译看左边,运行看右边。
父类
package cn.itcast.day10.demo05;
public class Fu {
int num = 10;
public void showNum(){
System.out.println(num);
}
public void method(){
System.out.println("父类方法");
}
public void methodFu(){
System.out.println("父类特有方法");
}
}
子类
package cn.itcast.day10.demo05;
public class Zi extends Fu{
int num = 20;
int age = 16;
@Override
public void showNum(){
System.out.println(num);
}
@Override
public void method(){
System.out.println("子类方法");
}
public void methodZi(){
System.out.println("子类特有方法");
}
}
main1方法,访问成员变量
package cn.itcast.day10.demo05;
public class Demo01MultiField {
public static void main(String[] args) {
// 使用多态的写法,父类引用指向子类对象
Fu obj = new Zi();
System.out.println(obj.num);
System.out.println("=======");
// 子类没有覆盖重写,就是父:10
// 子类如果覆盖重写,就是子:20
obj.showNum();
}
}
结果如下所示:
main方法,访问成员方法
package cn.itcast.day10.demo05;
public class Demo02MultiMethod {
public static void main(String[] args) {
Fu obj = new Zi();// 多态
obj.method();// 父子都有,优先用子
obj.methodFu();//子类没有,父类有,向上查找父类
// 编译看左边,运行看右边,左边是Fu,Fu当中没有methodZi方法,所以编译报错。
// obj.methodZi();
}
}
结果如下所示:
对象的向上、向下转型
实战一
父类
package cn.itcast.day10.demo06;
public abstract class Animal {
public abstract void eat();
}
子类1
package cn.itcast.day10.demo06;
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
// 子类特有方法
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
子类2
package cn.itcast.day10.demo06;
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃SHIT");
}
public void watchHouse(){
System.out.println("狗看家");
}
}
mian函数1
package cn.itcast.day10.demo06;
public class Demo01Main {
public static void main(String[] args) {
// 对象的向上的转型,就是:父类引用指向子类对象
Animal animal = new Cat();
animal.eat();// 猫吃鱼
// 向下转型,进行"还原"动作
Cat cat = (Cat) animal;
cat.catchMouse();// 猫抓老鼠
// 下面是错误的向下转型
// 本来new的时候是一只猫,非要当作狗
// 错误写法!编译不会报错,但是运行会出现异常
Dog dog = (Dog) animal;
}
}
运行结果
mian方法二
向下转型的判断
如何才能知道一个父类引用的对象,本来是什么子类?
格式:
对象 instanceof 类名称
这将会得到一个boolean值结果,也就是判断前面的对象能不能当做后面类型的实例。
package cn.itcast.day10.demo06;
public class Demo02Instanceof {
public static void main(String[] args) {
Animal animal = new Dog();
animal.eat();// 狗吃SHIT
// 如果希望调用子类特有的方法,需要向下转型
// 判断一下父类引用animal本来是不是Dog
if (animal instanceof Dog){
Dog dog = (Dog) animal;
dog.watchHouse();
}
// 判断一下animal本来是不是Cat
if (animal instanceof Cat){
Cat cat = (Cat) animal;
cat.catchMouse();
}
giveMeAPet(new Dog());
}
public static void giveMeAPet(Animal animal){
if (animal instanceof Dog){
Dog dog = (Dog) animal;
dog.watchHouse();
}
if (animal instanceof Cat){
Cat cat = (Cat) animal;
cat.catchMouse();
}
}
}
实战二(接口中的多态)
computer类
package cn.itcast.day10.demo07;
public class Computer {
public void powerOn() {
System.out.println("笔记本电脑开机");
}
public void powerOff() {
System.out.println("笔记本电脑关机");
}
// 使用USB设备的方法,使用接口作为方法的参数
public void useDevice(USB usb) {
usb.open(); // 打开设备
if (usb instanceof Mouse) { // 一定要先判断
Mouse mouse = (Mouse) usb; // 向下转型
mouse.click();
} else if (usb instanceof Keyboard) { // 先判断
Keyboard keyboard = (Keyboard) usb; // 向下转型
keyboard.type();
}
usb.close(); // 关闭设备
}
}
USB接口
package cn.itcast.day10.demo07;
public interface USB {
public abstract void open(); // 打开设备
public abstract void close(); // 关闭设备
}
键盘类实现USB接口
package cn.itcast.day10.demo07;
// 键盘就是一个USB设备
public class Keyboard implements USB {
@Override
public void open() {
System.out.println("打开键盘");
}
@Override
public void close() {
System.out.println("关闭键盘");
}
public void type() {
System.out.println("键盘输入");
}
}
鼠标类实现USB接口
package cn.itcast.day10.demo07;
// 鼠标就是一个USB设备
public class Mouse implements USB {
@Override
public void open() {
System.out.println("打开鼠标");
}
@Override
public void close() {
System.out.println("关闭鼠标");
}
public void click() {
System.out.println("鼠标点击");
}
}
main方法:
package cn.itcast.day10.demo07;
public class DemoMain {
public static void main(String[] args) {
// 首先创建一个笔记本电脑
Computer computer = new Computer();
computer.powerOn();
// 准备一个鼠标,供电脑使用
// Mouse mouse = new Mouse();
// 首先进行向上转型
USB usbMouse = new Mouse(); // 多态写法
// 参数是USB类型,我正好传递进去的就是USB鼠标
computer.useDevice(usbMouse);
// 创建一个USB键盘
Keyboard keyboard = new Keyboard(); // 没有使用多态写法
// 方法参数是USB类型,传递进去的是实现类对象
computer.useDevice(keyboard); // 正确写法!也发生了向上转型
// 使用子类对象,匿名对象,也可以
// computer.useDevice(new Keyboard()); // 也是正确写法
computer.powerOff();
System.out.println("==================");
method(10.0); // 正确写法,double --> double
method(20); // 正确写法,int --> double
int a = 30;
method(a); // 正确写法,int --> double
}
public static void method(double num) {
System.out.println(num);
}
}