🎇个人主页:Ice_Sugar_7
🎇所属专栏:快来卷Java啦
🎇欢迎点赞收藏加关注哦!
抽象类&接口1
- 🍉抽象类
- 🍌特性
- 🍌应用
- 🍉接口
- 🍌接口的特性
- 🍌使用接口
🍉抽象类
在面向对象的概念中,所有的对象都是通过类来描绘的,
但是不是所有的类都是用来描绘对象的。如果一个类没有包含足够的信息来描绘一个具体的对象,那它就叫作抽象类
比如说,Animal是动物类,每种动物都有不同的叫声,但由于Animal并不是具体的动物,所以其内部的bark方法没办法实现
而对于Dog类和Cat类,首先猫和狗都属于动物,那么它们和Animal类就是继承关系,而且它们都是具体的动物,所以它们的bark方法可以实现
上一篇文章打印图形的例子中,我们发现,父类 Shape 中的 draw 方法其实啥都没做,绘制图形的工作都是由Shape的子类的draw方法来完成的
public class Shape { public Shape shape; public void draw() { System.out.println("画一个图形"); } }
像这种没有实际工作的方法,我们可以把它设计成一个抽象方法(abstract method),包含抽象方法的类我们称为抽象类
abstract class Shape { int a; int b = 10; private double area; //抽象方法 abstract public void draw(); //可以在抽象类中实现普通方法 public double getArea() { //得到绘制的图形的面积 return this.area; } }
在Java中,一个类如果被 abstract 修饰,那就称为抽象类,抽象类中被 abstract 修饰的方法称为抽象方法,抽象方法不用给出具体的实现体(即没有方法体)
抽象类作为一种类,里面自然也可以添加普通方法和成员变量
🍌特性
-
不能实例化
刚才我们说抽象类无法描绘一个具体的对象,所以它不能实例化对象
-
抽象方法不能用private修饰
要被子类重写,肯定不能设为私有
-
抽象方法不能被final和static修饰
因为被final或static修饰的方法不能被重写,但是抽象方法在继承时要求子类重写该方法,所以final、static和abstract是天敌
-
抽象类必须被继承,并且继承后子类要重写父类中的抽象方法,否则子类也是抽象类,必须要使用 abstract 修饰
-
抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类
-
抽象类中可以有构造方法,供子类创建对象时,初始化父类的成员变量
🍌应用
因为抽象类不能实例化,所以要想使用的话,就要创建该抽象类的子类,然后让子类重写抽象类中的抽象方法
不过你可能会说:普通的类也可以被继承呀,普通的方法也可以被重写呀,为啥非得用抽象类和抽象方法呢?
因为使用抽象类相当于多了一重编译器的校验
比如上面画图形的例子,如果使用普通类进行继承,那不小心忘记重写子类的draw方法,那此时编译器是不会报错的
反之,如果是抽象类,编译器就会“逼你”重写
很多语法存在的意义就是为了“预防出错”
比如我们前面学过的 final 就是这样,创建的变量不希望被用户修改,所以加上 final ,这样就能够在不小心被修改的时候,让编译器及时提醒我们
充分利用编译器的校验, 在实际开发中是非常有意义的
🍉接口
如果将抽象类再进一步抽象化,就成了接口
抽象类中可以包含成员变量,但是接口不可以(不过仍然可以包含静态变量)
抽象类中可以实现非抽象方法,但是接口只能包含方法的声明。如果要实现方法,那只能实现静态方法
下面来看怎么实现一个接口
public interface 接口名称{// 抽象方法 public abstract void method1(); // public abstract 是固定搭配,可以不写 public void method2(); abstract void method3(); void method4(); // 注意:在接口中上述写法都是抽象方法,更推荐方式4,代码更简洁 }
public abstract编译器会默认给你加上的,所以不用写
关于接口的命名,需要注意:
- 创建接口时,接口的命名一般以大写字母 I 开头
- 接口的命名一般使用“形容词”词性的单词
- 接口中的方法和属性不要加任何修饰符号,保持代码的简洁性
接口有点类似C语言的头文件,因为头文件里面包含的就是函数声明,要具体实现这个函数的话,就得在其他源文件中实现
🍌接口的特性
- 接口是一种引用类型,但是不能直接new接口的对象
- 接口中每一个方法都是public的抽象方法,也就是说接口中每个方法默认都是public abstract修饰的。不能改为其他,否则会报错
- 接口中的方法不能在接口中实现的,只能由实现接口的类来实现
- 重写接口中方法时,不能使用默认的访问权限(default),一定要指定用public
- 接口中可以有变量,它们默认会被 public static final 修饰
public interface test2 { int a = 2; final public static double b = 3.0; }
- 接口中不能有静态代码块和构造方法
- 接口虽然不是类,但是接口编译完成后字节码文件的后缀格式也是.class
- 如果类没有实现接口中的所有的抽象方法,则类必须设置为抽象类
🍌使用接口
接口不能直接使用,必须要有一个“实现类”来实现该接口中所有抽象方法,实现接口需要用到关键字implements
接口是一种类型,它可以引用实现该接口的具体的类型
public class 类名称 implements 接口名称{// ... }
举个例子:
实现笔记本电脑使用USB鼠标和键盘
- USB接口:包含打开设备、关闭设备功能
- 笔记本类:包含开机功能、关机功能、使用USB设备功能
- 鼠标类:实现USB接口,并具备点击功能
- 键盘类:实现USB接口,并具备输入功能
这里的USB接口就是一个接口,它提供两种功能:连接设备、断开连接
public interface USB { void openDevice(); void closeDevice(); }
笔记本类需要根据接入接口的类(鼠标、键盘类),来调用相应的类的功能
public class Computer{ public void powerOn() { System.out.println("电脑开机"); } //因为鼠标类和键盘类都实现了USB接口,所以它们都能向上转型传参给usb public void useService(USB usb) { usb.openDevice(); if(usb instanceof Mouse) { Mouse mouse = (Mouse) usb; //向下转型,使用鼠标类特有的方法 mouse.click(); } else if (usb instanceof Keyboard) { Keyboard keyboard = (Keyboard) usb; keyboard.input(); } usb.closeDevice(); } public void powerOff() { System.out.println("电脑关机"); } }
鼠标和键盘实现基本的功能:
//鼠标类实现USB接口 public class Mouse extends Computer implements USB{ @Override public void openDevice() { System.out.println("连接鼠标"); } public void click() { System.out.println("使用鼠标点击"); } @Override public void closeDevice() { System.out.println("鼠标已断开连接"); } } //键盘类实现USB接口 public class Keyboard extends Computer implements USB{ @Override public void openDevice() { System.out.println("连接键盘"); } public void input() { System.out.println("使用键盘输入"); } @Override public void closeDevice() { System.out.println("键盘断开连接"); } }
接口解决了Java不支持多继承的问题
以动物类为例,我们想写一个Dog类来继承动物类,狗会跑,也会游泳。但不是所有动物都会这两种行为,而Java不支持多继承,但是支持一个类实现多个接口,所以我们可以把动物的行为封装成一个个接口
public class Animal { public String name; public int age; } //接口 public interface IFly { void Fly(); } public interface ISwimming { void swimming(); } public class Bird extends Animal implements IFly{ public String color; @Override public void Fly() { System.out.println(this.name + "正在振动翅膀飞翔"); } } //同时实现两个接口 public class Dog extends Animal implements IRun,ISwimming{ public String color; @Override public void run() { System.out.println(this.name + "正在跑"); } @Override public void swimming() { System.out.println(this.name + "正在游泳"); } }
小结:
- 接口表达的是某个类具有某种特性。有了接口,我们在使用类的时候就不用关注具体类型,只需关注某个类是否具备某种能力
- 方法的参数以接口类型作为形参,就可以接收所有实现这个接口的类类型(因为它们传参时会向上转型为接口类型)
比如前面USB接口的例子,鼠标、键盘类都可以向上转型为USB类,然后实现多态
-