1、接口可以理解为一个纯粹的抽象类(最原始的定义接口中只包含抽象方法和全局常量),但是从JDK1.8开始由于引入了Lambda表达式的概念,接口的定义也得到加强,其中还可以定义普通方法或静态方法。
2、interface关键字
interface IMessage { //定义一个接口
public static final String INFO = "hello" ; //全局常量
public abstract String getInfo() ; //抽象方法
}
3、①接口需要被子类实现(implements),一个子类可以实现多个父接口
②子类(如果不是抽象类)那么一定要覆写接口之中的全部抽象方法
class MessageImpl implements IMessage {
public String getInfo() {
return "一只瓶子a";
}
}
③接口对象可以利用子类对象的向上转型进行实例化。
IMessage msg = new MessageImpl();
System.out.println(msg.getInfo());
System.out.println(msg.INFO); //直接输出全局常量
④一个子类可以实现多个接口
当一个类实现多个子类时,对象实例化的过程:
IMessage msg = new MessageImpl() ;
IChannel ch1 = (IChannel)msg ;
System.out.println(ch1.connect());
由于MessageImpl子类实现了IMessage与IChannel两个接口,所以这个子类可以是这两个接口任意一个接口的实例,即此时这两个接口实例之间是可以相互转换的。
或者:
IMessage msg = new MessageImpl() ;
Object obj = msg ; //向上转型,本质上与IMessag接口并无关系
IChannel ch1 = (IChannel) obj ;
System.out.println(ch1.connect());
在java程序中接口是不允许去继承父类的,所以接口不是Object的子类。但是由于MessageImpl是Object的子类,所以接口可以通过Object接收。所以Object类可以接收接口对象。
4、接口描述的是一个公共的定义标准,所以接口中的所有抽象方法的访问权限都为public,可写可不写
简化定义:
interface IMessage { //定义一个接口
String INFO = "hello" ; //全局常量
String getInfo() ; //抽象方法
}
5、在开发过程中,实现接口的可能是抽象类,一个抽象类可以是实现多个接口,而一个普通类只能继承一个抽象类并且可以实现多个父接口,要求先继承后实现。接口不能继承父类,但是一个接口可以通过extends继承若干个父接口,此时称为接口的多继承。
6、接口的使用:
表示标准设置
表示一种操作能力
暴露远程方法视图(在RPC分布式开发中使用)
7、接口定义加强
为了解决有多个实现类后需要向接口中追加方法,又要避免在所有实现类里覆写新追加的方法是,在接口与实现子类之间增加抽象类,抽象类实现接口,并在抽象类中实现接口方法,而后原本的实现类继承该抽象方法。
从JDK1.8之后,为了解决接口设计的缺陷,所以在接口中允许定义普通方法。
接口中的普通方法必须追加default的声明,注意此操作仅是为解决上述问题,一般不作为首选。
public default boolean connect() {
方法体
}
除了普通方法,接口里也可以定义static方法,而static方法就可以通过接口直接调用了(无需实例化过程)。
8、使用接口定义标准
package com.demo;
// 接口——定义USB标准
interface IUSB {
public boolean check() ; //检查
public void work() ; //工作
}
class Keyboard implements IUSB {
public boolean check() {
return true ;
}
public void work() {
System.out.println("码字") ;
}
}
class print implements IUSB {
public boolean check() {
return false ;
}
public void work() {
System.out.println("打印") ;
}
}
class Computer {
public void plugin(IUSB usb) {
if(usb.check()) {
usb.work();
}else {
System.out.println("硬件出现问题") ;
}
}
}
public class JavaDemo {
public static void main(String[] args) {
Computer computer = new Computer();
computer.plugin(new Keyboard()); //插入键盘
computer.plugin(new print()); //插入打印机
}
}
9、工厂设计模式(Factory)
IFood food = new Bread();
food.eat(); //吃面包
IFood = new Rice();
food.eat(); //吃米饭
此时的程序中存在耦合问题,是由关键字new引起的。以JVM的设计为例,Java实现可移植性的关键在于JVM,而JVM的核心原理是利用一个虚拟机来运行Java程序,所有的程序并不与具体的操作系统有任何的关联,而是由JVM来进行匹配。良好的设计应该避免耦合。
增加一个类:
class Factory {
public static IFood getInstance(String className) {
if("bread".equals(className)) {
return new Bread() ;
}else if("rice".equals(className)){
return new Rice() ;
}else {
return null ;
}
}
}
此时,主类中:
IFood food = Factory.getInstance(args[0]);
food.eat() ;
此时,在程序运行时通过初始化参数进行要使用的子类定义。
10、代理设计模式(Proxy)
代理设计模式的主要功能是可以帮助用户将所有的开发注意力只放在核心业务功能的处理上。
代理设计模式的主要特点是,一个接口提供有两个子类,其中一个子类是真实业务操作类,另一个是代理业务操作类,没有代理业务操作,真实业务无法进行。
11、【重要】抽象类与接口的区别
区别:抽象类——接口
定义关键字:abstract class 抽象类名称 {}——interface 接口名称 {}
组成:构造方法,普通方法,静态方法,全局常量,普通成员——抽象方法,全局常量,普通方法,static方法
权限:可以使用各种权限定义——只能使用public
子类使用:子类通过exten关键字可以继承一个抽象类——子类通过implements关键字可以实现多个接口。
关系:抽象类可以实现若干个接口,接口不允许继承抽象类,但是允许继承多个父接口。
抽象类或接口必须定义子类;子类一定要覆写抽象类或接口中的全部抽象方法;通过子类的向上转型实现抽象类或接口对象实例化。
当抽象类和接口都可以使用时优先考虑接口,因为接口可以避免子类的单继承局限。
12、抽象类与接口的应用举例(管理工厂模式)——计算图像面积和周长
package com.demo;
// 抽象方法 定义图形标准
abstract class AbstractShap {
public abstract double area() ; // 面积
public abstract double preimeter() ; //周长
}
class Circular extends AbstractShap {
private double radius ;
public Circular(double radius) {
this.radius = radius ;
}
public double area() {
return 3.1415926 * this.radius * this.radius ;
}
public double preimeter() {
return 2 * 3.1415926 * this.radius ;
}
}
class Rectangle extends AbstractShap {
private double length ;
private double width ;
public Rectangle(double length, double width) {
this.length = length ;
this.width = width ;
}
public double area() {
return this.length * this.width ;
}
public double preimeter() {
return 2 * (this.length + this.width) ;
}
}
// 定义管理工厂
class Factory {
public static AbstractShap getInstance(String className,double ...args) {
if("circular".equalsIgnoreCase(className)) {
return new Circular(args[0]) ;
}else if("rectangle".equalsIgnoreCase(className)) {
return new Rectangle(args[0],args[1]) ;
}else {
return null ;
}
}
}
public class JavaDemo {
public static void main(String[] args) {
AbstractShap asa = Factory.getInstance("Circular",17) ;
AbstractShap asb = Factory.getInstance("Rectangle",1.0,7.0) ;
System.out.print(asa.area());
System.out.print(asb.area());
}
}