基本介绍
接口给出一些没有实现的方法,封装到一起,到某个类使用时再根据具体情况把这些方法写出来。
注意:在jdk7之前,接口里所有的方法都是抽象方法。在jdk8之后接口中可以有静态方法,默认方法
interface 接口名{
//属性
//方法
}
class 类名 implements 接口{
//自己的属性
//自己的方法
//必须实现的接口的抽象方法
}
例子
public interface AInterface{
//属性
int a=10;
//方法(抽象方法)
void b();
//jdk8之后接口中可以有默认方法
default public void c(){
System.out.println("hello");
}
//jdk8之后接口中可以有静态方法
public static void d(){
System.out.println("hi");
}
}
深入讨论
//项目经理写的
public interface DBInterface{
void connect();
void close();
}
//A程序员连接mysql
public class MysqlDB implements DBInterface{
@override
public void connect(){
System.out.println("连接mysql");
}
public void close(){
System.out.println("关闭mysql");
}
}
//B程序员连接Oracle
public class Oracle implements DBInterface{
@override
public void connect(){
System.out.println("连接Oracle");
}
public void close(){
System.out.println("关闭Oracle");
}
}
//运行数据库
public class InterfaceTest {
public static void main(String[] args) {
MysqlDB mysqlDB = new MysqlDB();
//调用方法
InterfaceTest interfacetest= new InterfaceTest();
interfacetest.work(mysqlDB);
}
public static void work(DBInterface db){
db.connect();
db.close();
}
}
运行结果
使用细节
1、接口中所有的方法都是publoc, 默认使用public abstract修饰方法
void a();
//实际上是
public abstract void a();
2、一个普通类实现接口就必须将该接口中的所有方法都实现,可以使用alt+enter
3、抽象类实现接口,可以不用实现接口中的方法。
4、一个类可以实现多个接口
class Pig implements A,B{
... ...
}
5、接口中所有的属性都是public, 默认使用public static final修饰属性,且必须初始化
public: 使接口的实现类可以使用这个常量
static:接口不涉及和任何具体实例相关的细节,因此接口没有构造方法,不能被实例化,没有实例变量,只有静态(static)变量。
static修饰就表示它属于类的,随的类的加载而存在的,当JVM把字节码加载进JVM的时候,static修饰的成员已经在内存中存在了。如果是非static的话,就表示属于对象的,只有建立对象时才有它,而接口是不能建立对象的,所以接口的常量必须定义为static。
final: 接口中不可以定义变量即定义的变量前都要加上final修饰,使之成为常量(没有final修饰的是变量,加上final修饰就会变成常量)。所以接口的属性默认是public static final 常量,且必须赋初值。( final修饰就是保证接口定义的常量不能被实现类去修改,如果没有final的话,由子类随意去修改的话,接口建立这个常量就没有意义了。)
int a=1;
//实际上是
public static final a=1;
6、接口不能继承类,但是可以继承多个其他接口。
interface A extends B,C{}
7、接口的修饰符只能是public和默认,这点和类的修饰符是一样的
接口VS继承
1、接口和继承解决的问题不同
继承的价值主要在于:解决代码的复用性和可维护性。
接口的价值主要在于:设计,设计好各种规范(方法),让其它类去实现这当方法。
2、接口比继承更加灵活
接口比继承更加灵活。继承是满足is - a的关系,而接口只需满足like - a的关系。
3、接口在一定程度上实现代码解耦
接口多态特性
1、为什么要用接口的引用指向它实现类的一个对象?
例如:List list = new ArrayList<String>();
而不使用:ArrayList list = new ArrayList<String>()
; 这样做的好处是什么?
这其实是Java中多态的一种表现。
接口的实现类可以有很多个,如 LinkedList
或者Vector
等等,如果使用这种方式,List list = new ArrayList<String>();
以后不想用ArrayList
了,直接改为你想用的实现类,如List list = new LinkedList<String>();
这样,虽然修改了实现类,但相关list
调用方法的代码是不用修改的;如果是ArrayList list = new ArrayList<String>();
这种写法,那就有可能要修改非常多代码了,因为,原本list调用了ArrayList
中的方法来实现某个功能,再修改实现类过后,list
原本调用的方法在LinkedList
中不存在,则还要修改对应调用的方法;
因此,两种方式其实都能实现同一种效果,只是接口的引用指向实现类对象这一方法,是用接口来规范了实现的方法,这样子写的化就很清楚的知道哪些方法有,哪些方法没有。
这就是一种设计规范,如果按照这种设计规范来写,就可以免去在修改实现的对象调用方法不存在的情况。这样写的好处是便于程序代码的重构. 这就是面向接口编程的好处。
【注意】
list
只能使用ArrayList
中已经实现了的List
接口中的方法,ArrayList
中那些自己的、没有在List
接口定义的方法是不可以被访问到的
list.add()
其实是List
接口的方法,但是调用ArrayList
的方法如 clone()
方法是调用不到的
总结:java在利用接口变量调用其实现类的对象的方法时,该方法必须已经在接口中被声明,而且在接口的实现类中该实现方法的类型和参数必须与接口中所定义的精确匹配。
接口的灵活性就在于“规定一个类必须做什么,而不管你如何做”。
我们可以定义一个接口类型的引用变量来引用实现接口的类的实例,当这个引用调用方法时,它会根据实际引用的类的实例来判断具体调用哪个方法
2、多态参数(如下)
例一:
interface既可以接收手机的对象,又可以接收相机的对象
public interface Usbinterface {
void start();
void stop();
}
public class Phone implements Usbinterface{
@Override
public void start() {
System.out.println("手机开始工作");
}
@Override
public void stop() {
System.out.println("手机停止工作");
}
}
public class Computer {
public static void main(String[] args) {
//拿出一个实现USB接口的手机
Phone phone=new Phone();
//拿出一个电脑
Computer computer=new Computer();
//把手机与电脑连接
computer.work(phone);
}
//编写方法,使用了多态
public void work(Usbinterface usbinterface){//可以接收实现了Usbinterface接口的类的对象实例。
usbinterface.start();
usbinterface.stop();
}
}
例二:
public class InterfacePolyParameter {
public static void main(String[] args) {
//接口的多态体现
//接口类型的变量fly可以指向实现了Fly接口的对象实例
Fly fly=new Monster();
fly=new Bird();
}
}
interface Fly{}
class Monster implements Fly{}
class Bird implements Fly{}
例三:
public class InterfacePolyArr {
public static void main(String[] args) {
//多态数组->接口类型的数组
Usb[] usbs=new Usb[2];
usbs[0]=new MacBook_Air();
usbs[1]=new MacBook_Pro();
//给Usb数组中,存放 Phone和相机对象,Phone类还有一个特有的方法call () ,
// 请遍历Usb数组,如果是Phone对象,除了调用Usb接口定义的方法外,
//还需要调用MacBook_Air特有的方法show()
for (int i = 0; i < usbs.length; i++) {
usbs[i].work();//动态绑定..
//和前面一样,我们仍然需要进行类型的向下转型
if (usbs[i] instanceof MacBook_Air){//instanceof是判断运行类型是MacBook_Air
((MacBook_Air) usbs[i]).show();
}
}
}
}
interface Usb{
void work();
}
class MacBook_Air implements Usb{
public void show(){
System.out.println("超轻薄笔记本");
}
@Override
public void work() {
System.out.println("MacBook_Air工作");
}
}
class MacBook_Pro implements Usb{
@Override
public void work() {
System.out.println("MacBook_Pro工作");
}
}
接口多态传递
通过extends传递
public class InterfacePolyPass {
public static void main(String[] args) {
//接口类型的变量可以指向,实现了该接口的类的对象实例
BB bb=new Person();
//则实际上相当于Person类也实现了AA接口
AA aa=new Person();
}
}
interface AA{}
interface BB extends AA{}//这里就传递了
class Person implements BB{}