接口
/*1.接口:告诉有什么方法;
2.实现者:implements,实现了接口中的方法;
3.使用者:调用接口,使用接口方法。
*/
//sort排序方法的对象需要实现comparable类。
一、什么是接口
接口相当于特殊的抽象类,定义方式、组成部分与抽象类类似。
微观概念:接口是一种能力和约定。
接口的定义:代表了某种能力。
方法的定义:能力的具体要求。
宏观概念:接口是一种标准。
接口的语法:
接口相当于特殊的抽象类,定义方式、组成部分与抽象类似。
公开静态常量:静态(类),最终(无法修改)的。不必创建对象。
公开抽象方法:更自然的使用多态,不能创建对象。
interface MyInterface{//使用interface关键字定义接口
//只能定义:公开静态变量、公开抽象方法
//没有构造方法,不能创建对象,例如不能new父类
//公开静态常量
public static final String FIELD = "value";
//或者简单写,(默认)隐式存在公开静态常量
String FIELD2 = "Hi";
//公开抽象方法
public abstract void method();
//或者简单写,(默认)隐式存在公开公开抽象方法
void method2();
}
二、与抽象类的异同
相同:
- 可编译成字节码文件。
- 不能创建对象。
- 可以作为引用类型。
- 具备Object类中所定义的方法。
不同:
- 所有属性都是公开静态常量,隐式使用public static final修饰。
- 所有方法都是公开抽象方法,隐式使用public abstract修饰。
- 没有构造方法、动态代码块、静态代码块。
//抽象类
abstract class MyClass {
static int a;//类可以定义,接口不行。jdk1.8之后有静态方法和默认方法。
//1.(抽象方法)不能new对象(对象不能独立存在,不能使用构造方法)
public static final String FIELD = "Hello";
//2.抽象方法(子类必须覆盖)public abstract void m1();
public abstract void method();
}
//接口
interface MyInterface {
//1.公开静态常量
public static final String FIELD = "Hello";
//或者简单写,(默认)隐式存在公开静态常量
String FIELD2 = "Hi";
//2.公开抽象方法
public abstract void method();
//或者简单写,(默认)隐式存在公开公开抽象方法
void method2();
}
//测试类
public class TestBasicInterface {
public static void main(String[] args){
}
}
三、接口的应用
接口的规范:
//实现抽象类,修饰符必须为public
- 任何类在实现接口时,必须实现接口中的所有抽象方法,否则此类为抽象类。
- 实现接口中的抽象方法时,访问修饰符必须是public。
单继承与多继承:
//接口实现超脱了父类约定的抽象方法
- Java为单继承,当父类的方法种类无法满足子类需求时,可实现接口扩充子类能力。
- 接口支持多实现,可为类扩充多种能力
类与类:
单继承
extends 父类名称
类与接口:(实现关系)
多实现
implements 接口名称1,接口名称2,接口名称n
接口与接口:(继承关系)
多继承
extend 父接口1,父接口2,父接口n
//父类
abstract class Animal1 {
String breed;
int age;
String sex;
//抽象方法(规定子类必须存在的行为、规范了该行为的具体要求)
public abstract void eat();
public abstract void sleep();
}
//接口
//Runnable接口
//接口是一种能力
public interface Runnable {
//接口(中的方法)是一种约定
public abstract void run();
}
//Swimmable接口
public interface Swimmable {
public abstract void swim();
}
//Climbable接口
public interface Climbable {
public abstract void climb();
}
//子类
//猫
public class Cat1 extends Animal1 implements Runnable,Climbable{//多实现
String furColor;
public void eat(){
}
public void sleep(){
}
//独有方法
public void run(){
}
public void climb(){
}
}
//狗
public class Dog1 extends Animal1 implements Runnable{//实现
String furColor;
public void eat(){
}
public void sleep(){
}
//独有方法
public void run(){
}
}
//鱼
public class Fash1 extends Animal1 implements Swimmable{
public void eat(){
}
public void sleep(){
}
//独有方法
public void swim(){
}
}
接口引用:
同父类一样,接口也可声明为引用,并指向实现类对象。
注意://可进行拆箱即向下转型来调用未声明的方法(独有方法)。
- 仅可调用接口中所声明的方法,不可调用实用类中独有的方法。
- 可强转实现类本身类型,进行独有方法调用。(拆箱)
接口的多态:
接口引用指向实现类对象
多种不同类型的引用指向同一个对象时,表示看待对象的视角不同。
不同引用所能看到的对象范围不同,只能调用自身类型中所声明的部分。
总之,不同引用类型,仅可调用自身类型中所声明的方法。
类的多态:父类引用指向子类对象。//狗是一种动物(把狗当成动物来看)
接口的多态:接口引用指向实现类对象。//狗是一种会跑的东西(把狗当成一种会跑的东西来看待)
//同上一例子
//测试类
//父类比接口范围更泛
public class TestAble {
public static void main(String[] args){//使用者
//狗是一种动物(把狗当成动物来看)
Animal1 animal1 = new Dog1();//父类引用指向子类对象(多态)
//向下转型
((Dog1) animal1).run();
//狗是一种会跑的动物(把狗当成一种会跑的东西来看待)
Runnable r = new Dog1();//接口引用指向实现类对象(更自然的多态)
r.run();
Runnable r2 = new Bus();
r2.run();
//r中存储了一个会跑的东西,我需要调用接口以外的内容
Dog1 mydog = (Dog1) r;
//拆箱(向下转型)
mydog.eat();
//((Dog1) r).eat();
mydog.sleep();
//当然这样也可以,但是不提倡,不符合多态、继承的思想
//Dog1 dog1 = new Dog1();
//dog1.eat();
}
}
}
//Runnable接口
//接口是一种能力
public interface Runnable {
//接口(中的方法)是一种约定
public abstract void run();
}
//Bus类
public class Bus implements Runnable {//实现者
@Override
public void run() {
System.out.println("以每小时1m狂飙");
}
}
四、常量、标记接口
常量接口:
将多个常用于表示状态或固定值的变量,以静态常量的形式定义在接口中统一管理, 提高代码可读性。
public interface Light {
public static final int RED = 1;
int YELLOW = 2;
int GREEN = 3;
}
public class TestInterfaceExtends {
public static void main(String[] args){
int currentLight = Light.GREEN;//直接类名.调用
int currentLight2 = Light.RED;
int currentLight3 = Light.YELLOW;
}
}
//利用枚举
//枚举,规范了取值的类型
public enum Light1 {
GREEN,YELLOW,RED
}
public class TestInterfaceExtends {
public static void main(String[] args){
Light1 currentLight4 = Light1.GREEN;//枚举
}
}
标记接口:
接口没有任何成员,仅仅是一个标记。Serializable、Cloneable
五、回调原理:
宏观概念:接口是一种标准。
接口回调:先有接口,先有接口的使用者,后有接口的实现者。
//implements为实现者。
//创建对象,使用接口为使用者。
public class TestUSB{
public static void main(String[] args){
//程序猿
Computer c1 = new Computer();
c1.on(new Fan() , new Lamp() , new UDisk() );//使用工具
}
}
class Computer{//工具
USB u1;
USB u2;
USB u3;
public void on(USB u1 , USB u2 , USB u3){
this.u1 = u1;
this.u2 = u2;
this.u3 = u3;
System.out.println("开机,进入操作页面...");
//接口的使用者
u1.service();
u2.service();
u3.service();
}
}
interface USB{
//服务
public void service();
}
class Fan implements USB{
public void service(){
System.out.println("旋转...");
}
}
class Lamp implements USB{
public void service(){
System.out.println("照明...");
}
}
class UDisk implements USB{
public void service(){
System.out.println("读写数据...");
}
}
六、JDK1.8接口变化
1.提供了静态方法和默认方法,分别使用 static 和 default 关键字修饰,这两种方法可以有方法体 (下面是需要注意的地方)。
[1]:default 方法属于实例,static 方法属于接口或类。要注意的是:default 方法可以被继承,static 方法不会。
[2]:如果一个类实现了多个接口,并且这些接口之间没有相互继承关系,同时存在相同的 default 方法时会报错,不过你可以在实现类中重写 default 方法并通过 <接口>.super.<方法名>(); 形式指定调用哪个父接口中的 default 方法。
2.如果一个接口只有一个抽象方法,那么这个接口会默认自动变成函数式接口。
3.如果使用了@FunctionalInterface 注解对接口进行修饰,说明这个接口是一个函数式接口,在该接口只能有一个抽象方法 (不限制静态方法和默认方法)。一个函数式接口可以通过 Lambda 表达式来创建该接口的对象。
//[1]
public interface TestInterface {
static void testStaticMethod(){
System.out.println("static method run");
}
default void testDefaultMethod(){
System.out.println("default method run");
}
}
class Test implements TestInterface {
public static void main(String[] args) {
Test test = new Test();
test.testDefaultMethod();//default 方法可以被继承,static 方法不会。
//test.testStaticMethod(); Static method may be invoked on containing interface class only
TestInterface.testStaticMethod(); //对于接口中的静态方法可以使用接口名直接调用
}
}
输出
default method run
static method run
//[2]
public interface TestInterface {
default void testDefaultMethod(){
System.out.println("TestInterface default method run");
}
}
interface TestInterface1{
default void testDefaultMethod(){
System.out.println("TestInterface1 default method run");
}
}
class Test implements TestInterface,TestInterface1 {//在实现类中重写 default 方法并通过 <接口>.super.<方法名>(); 形式指定调用哪个父接口中的 default 方法
public void testDefaultMethod(){
TestInterface1.super.testDefaultMethod();
}
public static void main(String[] args) {
Test test = new Test();
test.testDefaultMethod();
}
}
输出
TestInterface1 default method run
//2、3
@FunctionalInterface
public interface TestFunctionalInterface {//函数式接口,在该接口只能有一个抽象方法
static void staticMethod(){} //在函数式接口中不限制定义静态方法与默认方法
default void defaultMethod(){}
void functionalInterfaceMethod();
// void functionalInterfaceMethod2(); 不允许
}
接口的好处:
- 程序的耦合度降低。
- 更自然的使用多态。
- 设计与实现完全分离。
- 更容易搭建程序框架。
- 更容易更换具体实现。
七、总结:
什么是接口:
- 微观:接口是一种能力和约定。
- 宏观:接口是一种标准。
接口与类的异同:
没有构造方法,仅可定义公开静态常量与公开抽象方法。
接口的应用:
Java为单继承,当父类的方法种类无法满足子类需求时,可实现接口扩充子类能力。
接口的规范:
任何类在实现接口时,必须实现接口中所有的抽象方法,否则此类为抽象类。
实现接口中的抽象方法时,访问修饰符必须是public。
什么是常量接口:
将多个常用于表示状态或固定值的变量,以静态常量的形式定义在接口中统一管理。
什么是接口回调:
先有接口的使用者,后有接口的实现者。
八、面向对象的设计原则
口诀:开口里合最单依
总则:
开闭原则
单一职责原则
里氏替换原则
依赖倒置原则
接口隔离原则
迪米特法则(最小知道原则)
合成复用原则