接口
定义
接口相当于特殊的抽象类,定义方式、组成部分与抽象类类似。没有构造方法,不能创建对象.只能定义:公开静态常量、公开抽象方法
特点
- 使用interface关键字定义接口
- interface 接口名{}
- 接口中abstract关键字可以省略
- 类实现接口使用implements表示
- class 类名 implements 接口名 {}
- 接口不能实例化
- 接口按照多态的形式实例化
- 接口的子类
- 可以是接口,使用extends继承
- 可以是抽象类,但是意义不大
- 可以是实体类,需要重写接口中所有的抽象方法(使用最多)
- 接口中的成员变量必须是静态的、最终、公共的,也就是常量
- public、static、final关键字可以省略
public interface MyInterface {
//公开的静态常量
String num = "vadv";
//公开的抽象方法
void method();
}
通过implements实现接口,并且重写所以接口中的方法
public class TestInterface {
public static void main(String[] args) {
//接口 变量=new 实现接口的类
MyInterface myInterface = new Impl();
//调用方法
myInterface.method();
}
}
class Impl implements MyInterface {
//覆盖接口method方法
@Override
public void method() {
System.out.println("实现接口");
}
}
//接⼝1
public interface MyInterface {
//定义了静态常量 static final 可以省略
static final String NAME = "⼩红";
//定义了抽象⽅法
public void method();
//定义了抽象⽅法
public void method2();
}
//接⼝2 继承了接⼝1
public interface MyInterface2 extends MyInterface {
//定义了抽象⽅法
public void method2();
}
//定义实现类实现接⼝
public class MyInterfaceSon implements MyInterface2{
//重写抽象⽅法
@Override
public void method() {
System.out.println("重写method抽象⽅法");
}
//重写抽象⽅法
@Override
public void method2() {
System.out.println("重写method2抽象⽅法");
}
}
好处
- 降低程序的耦合度
- 更自然的使用多态
- 设计和实现完全分离
- 更加容易搭建程序框架
- 更加容易更换具体实现
接口与类的异同
类与类
- 继承关系只能单继承,不能多继承,但是可以多层继承
- 多继承:子类继承父类,父类继承祖父类
- 如果多个父类出现相同的方法,无法区分
类与接口
- 实现关系可以单实现,也可以多实现,在继承的同时可以多实现
- 多个接口出现了名称、参数列表相同的方法,但是返回值不同,会报错
接口与接口
- 继承关系,可以单继承,也可以多继承
- 如果多个父类出现了相同的,子类用谁都可以
接口与抽象类
相同:
- 可编译成字节码文件。
- 不能创建对象。
- 可以作为引用类型。
- 具备Object类中所定义的方法。
不同:
- 所有属性都是公开静态常量,隐式使用public static final修饰。
- 所有方法都是公开抽象方法,隐式使用public abstract修饰。
- 没有构造方法、动态代码块、静态代码块。
- 一个类只能继承一个抽象类,但是一个类可以实现多个接口
- 抽象类有实例变量,接口只有类变量
为解决多继承关系,Java8提供了下⾯三条规则:
- 类中的⽅法优先级最⾼,类或⽗类中声明的⽅法的优先级⾼于任何声明为默认⽅法的优先
级。 - 如果第⼀条⽆法判断,那么⼦接⼝的优先级更⾼:⽅法名相同时,优先选择拥有最具体实现的默认⽅法的接⼝, 即如果B继承了A,那么B就⽐A更加具体。
- 如果还是⽆法判断,继承了多个接⼝的类必须通过显式覆盖和调⽤期望的⽅法, 显式地选择使⽤哪⼀个默认⽅法的实现。
public interface A {
default void hello() {
System.out.println("hello from A");
}
}
public interface B extends A {
default void hello() {
System.out.println("hello from B");
}
}
public class C implements A, B {
public static void main(String[] args) {
new C().hello();
}
}
因为B继承了A,所以B⽐A更具体,所以应该选择B的hello()⽅法。所以,程序会打印输
出"hello from B"。
public interface A {
default void hello() {
System.out.println("hello from A");
}
}
public interface B extends A {
default void hello() {
System.out.println("hello from B");
}
}
public class D implements A {
}
public class C extends D implements A, B {
public static void main(String[] args) {
new C().hello();
}
}
C虽然继承了D,但D中未覆盖A的默认⽅法,接着,编译器会在A和B中做选择,由于B更具体,所以,程序会打印输出"hello from B"。
public interface A {
default void hello() {
System.out.println("hello from A");
}
}
public interface B extends A {
default void hello() {
System.out.println("hello from B");
}
}
public class D implements A {
public void hello() {
System.out.println("hello from D");
}
}
public class C extends D implements A, B {
public static void main(String[] args) {
new C().hello();
}
}
⽗类中声明的⽅法具有更⾼的优先级,所以程序会打印输出"hello from D"。
public interface A {
default void hello() {
System.out.println("hello from A");
}
}
public interface B {
default void hello() {
System.out.println("hello from B");
}
}
public class C extends D implements A, B {
public static void main(String[] args) {
new C().hello();
}
}
由于编译器⽆法识别A还是B的实现更加具体,所以会抛出编译错误:”C inherits unrelateddefaults for hello() from types A and B“。
像这种场景要解决冲突,可以在C中覆盖hello()⽅法并在⽅法内显示的选择调⽤A还是B的⽅法。
public class C extends D implements A, B {
public void hello() {
// 显式地选择调⽤接⼝B中的⽅法
// 同理,要调⽤接⼝A中的⽅法,可以这样:A.super.hello()
B.super.hello();
}
public static void main(String[] args) {
// 输出 hello from B
new C().hello();
}
}
public interface A {
default void hello() {
System.out.println("hello from A");
}
}
public interface B extends A{
}
public interface C extends A{
}
public class D implements B, C {
public void hello() {
new D().hello();
}
}
只有⼀个⽅法申明可以选择,所以程序会输出"hello from A"。
默认方法
在1.8以后,接口中存在默认的方法
public interface Sized {
// 普通抽象⽅法,默认是public abstract修饰的,没有⽅法体
int size();
/*
* 默认⽅法,有⽅法体
* 任何⼀个实现了Sized接⼝的类都会向动继承isEmpty的实现
*/
default boolean isEmpty() {
return this.size() == 0;
}
}
应用
//飞翔接口
public interface MyInterface {
void fly();
}
public class TestInterface {
public static void main(String[] args) {
Impl impl = new Impl("jack");
impl.fly();
System.out.println("*****使用多态********");
MyInterface myInterface = new Impl("mkie");
myInterface.fly();
}
}
class Impl implements MyInterface {
String name;
//带参构造方法
public Impl(String name) {
this.name = name;
}
//覆盖原来fly方法,实现方法体
@Override
public void fly() {
System.out.println(name + "在飞翔");
}
}
规范
- 任何类在实现接口时,必须实现接口中所有的抽象方法,否则此类为抽象类。
- 实现接口中的抽象方法时,访问修饰符必须是public。
引用
- 同父类一样,接口也可声明为引用,并指向实现类对象。interface 对象名 = new 实现类()
- 仅可调用接口中所声明的方法,不可调用实现类中独有的方法。
- 可强转回实现类本身类型,进行独有方法调用。
- 特殊:通过接口可调用0bject中的公开方法]
接口的多态
//飞翔接口
interface MyInterface {
void fly();
}
//父类:抽象类
abstract class Animal {
public void eat() {
System.out.println("吃......");
}
}
//子类继承父类,并且时间接口
class Dog extends Animal implements MyInterface {
@Override
public void fly() {
System.out.println("飞翔....");
}
//子类特有方法
public void run() {
System.out.println("跑.....");
}
}
class Test {
public static void main(String[] args) {
Dog dog = new Dog();
dog.run();
System.out.println("****以下是多态****");
Animal animal = new Dog();
animal.eat();
MyInterface myInterface = new Dog();
myInterface.fly();
}
}
常见关系
- 类与类
- 单继承 extends 父类名称
- 类与接口
- 多实现 implements 接口名称1,接口名称2,接口名称n
- 接口与接口:
- 多继承 extends父接口1,父接口2,父接口n
常量接口、标记接口
常量接口将多个常用于表示状态或固定值的变量,以静态常量的形式定义在接口中统一管理;提高代码可读性。
//常量接口
public interface ConstInterface {
String CONST="AAA";
}
class TestConstInterface{
public static void main(String[] args) {
if (ConstInterface.CONST.equals("AAA")){
System.out.println(ConstInterface.CONST);
}
}
}
标记接口中没有包含任意成员,仅仅用作标记。
Serializable:序列化
Cloneable:克隆
接口回调
class TestUsb {
public static void main(String[] args) {
//实例化
Computer computer = new Computer();
Usb mouse = new Mouse();
Usb fan = new Fan();
Usb Upan = new Upan();
//将usb1、2、3赋值,在run方法在判断,只要不为空,就会根据数据类型调用service()
computer.usb1 = Upan;
computer.usb2 = fan;
computer.usb3 = mouse;
computer.run();
}
}
public interface Usb {
void service();
}
class Upan implements Usb {
@Override
public void service() {
System.out.println("U盘连接电脑成功,开始工作。。。");
}
}
class Fan implements Usb {
@Override
public void service() {
System.out.println("风扇连接电脑成功,开始工作。。。");
}
}
class Mouse implements Usb {
@Override
public void service() {
System.out.println("鼠标连接电脑成功,开始工作。。。");
}
}
class Computer {
Usb usb1;
Usb usb2;
Usb usb3;
public void run() {
System.out.println("电脑开始工作......");
if (usb1 != null) {
usb1.service();
}
if (usb2 != null) {
usb2.service();
}
if (usb3 != null) {
usb3.service();
}
}
}
总结
什么是接口
微观:接口是一种能力和约定。
宏观;接口是一种标准。
接口与类的异同
没有构避方法,仅可定义公开静态常量与公开抽象方法。
接口的应用
Java为单继承,当父类的方法种类无法满足子类需求时,可实现接口扩充子类能力。
接口的规范
任何类在实现接口时,必须实现接口中所有的抽象方法,否则此类为抽象类。
实现接口中的抽象方法时,访问修饰符必须是public。
什么是常量接口
将多个常用于表示状态或固定值的变量,以静态常量的形式定义在接口中统一管理。
什么是接口回调
先有接口的使用者,后有接口的实现者。
接口的好处
程序的耦合度降低。
更自然的使用多态。
设计与实现完全分离。
更容易搭建程序框架。
总结
什么是接口
微观:接口是一种能力和约定。
宏观;接口是一种标准。
接口与类的异同
没有构避方法,仅可定义公开静态常量与公开抽象方法。
接口的应用
Java为单继承,当父类的方法种类无法满足子类需求时,可实现接口扩充子类能力。
接口的规范
任何类在实现接口时,必须实现接口中所有的抽象方法,否则此类为抽象类。
实现接口中的抽象方法时,访问修饰符必须是public。
什么是常量接口
将多个常用于表示状态或固定值的变量,以静态常量的形式定义在接口中统一管理。
什么是接口回调
先有接口的使用者,后有接口的实现者。
接口的好处
程序的耦合度降低。
更自然的使用多态。
设计与实现完全分离。
更容易搭建程序框架。
更容易更换具体实现。