抽象类和接口
抽象类
引出:当父类的某些方法需要申明,但又不确定如何实现的时候,可以把这个类变成抽象类 添加 abstract关键字
抽象类和普通类最大的区别:抽象类不能被实例化;抽象类可以有抽象方法
抽象类和抽象方法的关系:抽象类一般会包含抽象方法,抽象方法一定位于抽象类或者接口中
public class AbstractDemo {
public static void main(String[] args) {
// 抽象类不能被实例化
// AbstractClassExample ac1 = new AbstractClassExample();
// 抽象类会被继承,由自己的子类实现方法
AbstractClassExample ac2 = new AbstractExtendClassExample();
// 能直接通过类名.静态属性/静态方法来访问抽象类中的静态属性/静态方法
System.out.println(AbstractClassExample.x);
Animal.func3();
}
}
// 抽象类: 访问修饰符 abstract class 类名{} (class 关键字要放在 abstract关键字后面)
// 抽象类的本质还是类可以有方法,属性,代码块,构造器,但是抽象类不能被实例化
public abstract class AbstractClassExample {
// 属性
private int y;
// 静态属性
public static int x;
// 构造器:可以被子类用super关键字调用构造器
public AbstractClassExample(){}
// 代码块
{}
// 抽象方法:不能使用private,final和static修饰符,因为这些修饰符都是和重写相违背的
// 访问修饰符 abstract 返回类型 方法名(参数列表); // 没有方法体
public abstract void func1();
// 普通方法
public void func2() {
System.out.println("func2");
}
// 静态方法
public static void func3() {
System.out.println("func3");
}
}
// 继承抽象类,必须重写该抽象类的抽象方法
class AbstractExtendClassExample extends AbstractClassExample {
@Override
public void func1() {
System.out.println("func1");
}
}
// 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract;如果子类实现抽象类的全部抽象方法,则子类的子类就不需要实现了该抽象类的抽象方法
abstract class AbstractExtendAbstractClassExample extends AbstractClassExample {}
接口
接口的概述
概念:接口不是类,而是对希望符合这个接口的类的一组需求,接口是抽象类的延伸,接口是弥补抽象类不能实现多继承的缺点
在jdk8之前都是没有方法体的抽象方法;自从jdk8开始,接口的方法可以有具体实现,但是必须是静态方法或者是默认方法(添加default关键字)
// 访问修饰符 interface 接口名{} 访问修饰符:public 和默认
interface Interface{
// 静态属性 默认是public static final修饰
int n1 = 10;
// 静态内部类 默认是public static final修饰,可以实现当前接口
class InterfaceInnerClass{};
// 静态方法 默认是public修饰
static void method3(){
System.out.println("静态方法");
}
// 抽象方法 默认是public abstract
void method1();
// 默认方法 添加default关键字 默认是public
default public void method2(){
System.out.println("默认方法");
}
}
// class 类名 implements 接口
class ImplInterface implements Interface{
// 必须实现的抽象方法
public void method1() {};
public static void main(String[] args) {
// 接口不能被实例化
// Interface interfaces = new Interface(); error
// 可以实现接口的静态内部类
Interface.InterfaceInnerClass innerClass = new Interface.InterfaceInnerClass();
innerClass.method3();
// 可以通过接口名.静态方法名来调用静态方法 接口名.属性名来访问属性
Interface.method3();
System.out.println(Interface.n1);
}
}
// 一个非抽象类实现了该接口就必须实现该接口上的所有抽象方法,抽象类去实现接口时候,可以不用实现接口的抽象方法
abstract class AbstractImplInterface implements Interface{}
注意:一个类同时可以实现多个接口,一个接口不能继承其他的类,但是可以继承多个其他接口
// 接口 <-> 接口 AND 类 <-> 类 称 继承
// 类 -> 接口 称 实现
// 顶级接口
interface top{}
// 父级接口 一个接口不能继承其他的类,但是可以继承多个其他接口
interface secondTop extends top{}
//另外一个接口
interface another{}
// 实现类 一个类同时可以实现多个接口
class imp implements secondTop,another{}
接口的多态性
// Usb接口
public interface UsbInterface {
// 规定相关接口的方法
public void start();
public void end();
}
// 相机实现了该接口
public class Camera implements UsbInterface{
@Override
public void start() {
System.out.println("照相机开始运行了~");
}
@Override
public void end() {
System.out.println("照相机开始关机了~");
}
}
// 手机实现了该接口
public class Phone implements UsbInterface{ // 实现接口
@Override
public void start() {
System.out.println("手机开始运行了~");
}
@Override
public void end() {
System.out.println("手机开始关机了~");
}
}
// 接口插入,分别实现不同功能
public class Computer {
// 计算机工作
public void work(UsbInterface usbInterface){
usbInterface.start();
usbInterface.end();
}
}
public class Interface01 {
/*
* 接口多态特性
* 1)既可以接收手机对象,又可以接受相机对象,就体现了接口多态(接口引用可以指向实现了该接口的类的对象)
* 2)多态数组
* usbs[i] instanceof Phone 向下转型,判读Usb接口是否为Phone
* 接口类型的变量可以指向实现了该接口的类的对象的实例
*/
public static void main(String[]args){
// 创建手机和相机对象
Camera camera = new Camera();
Phone phone = new Phone();
// 创建电脑对象
Computer computer = new Computer();
// 插入接口,相机和手机分别运作
computer.work(phone);
computer.work(camera);
// 多态数组
UsbInterface[] UsbS = new UsbInterface[2];
UsbS[0] = new Phone();
UsbS[1] = new Camera();
for (int i = 0; i < UsbS.length; i++) {
computer.work(UsbS[i]);
}
}
}
接口实现 Vs 继承类
- 接口和继承解决的问题不同 继承的价值主要在于:解决代码的复用性和可维护性 接口的价值主要在于:设计好各种规范(方法),让其他类去实现这些方法
- 接口比继承更加灵活 继承满足is-a的关系,而接口只需满足like-a的关系
- 接口在一定程度上实现代码解耦[接口的规范性+动态绑定]
抽象类 Vs 接口
- 从设计层面上看,抽象类提供了一种 IS-A 关系,那么就必须满足里式替换原则,即子类对象必须能够替换掉所有父类对象。而接口更像是一种 LIKE-A 关系,它只是提供一种方法实现契约,并不要求接口和实现接口的类具有 IS-A 关系
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口
- 接口的成员只能是 public 的,而抽象类的成员可以有多种访问权限(接口不能有代码块,抽象类和普通类就是多了抽象方法)
- 抽象可以有普通方法(含有方法体),接口只能是默认方法(带有default关键字)
使用选择
使用接口:
- 需要让不相关的类都实现一个方法,例如不相关的类都可以实现 Compareable 接口中的 compareTo() 方法
- 需要使用多重继承(通过多个接口实现弥补单继承)
使用抽象类:
- 需要在几个相关的类中共享代码
- 需要能控制继承来的成员的访问权限,而不是都为 public