java接口详解


文章内容选自尚硅谷,jdk8,eclipse环境

java接口简介

java接口可以用来解决类的单继承问题,一般是把多个不同类共同的方法提取出来,形成一种规范、接口,只要用到了这些方法,都要调用该接口。并在实现类中重写接口定义的方法。

JDK7及以前,只能定义全局常量和抽象方法
全局常量:用static final修饰的变量
抽象方法:用abstract修饰的方法

JDK8及以后,接口内还可以定义静态方法和默认方法。

以下先介绍JDK7及以前的形式。

接口内的书写形式

  • 接口和类是并列的两个结构,用interface关键字修饰。
  • 接口中不能定义构造器,意味着接口不可以实例化。

JDK7以前方法必须是抽象方法,变量必须是全局常量,为了简便书写,编译器在遇见不加关键字修饰的变量和方法的时候,会默认将其视为全局常量和抽象方法。

public class InterfaceTest {

}

interface Flyable{
	public static final int MAX_SPEED = 7900;
	int MIN_SPEED = 1;
	
	public abstract void fly();
	void stop();
}

接口的变量MIN_SPEED其实也是全局常量,省略掉了public static final关键字
接口的方法stop方法其实也是抽象方法,省略掉了public abstract关键字

接口被类实现

因为接口是和类并列的结构,但是又不能实例化,那么接口就只能被类实现,有点类似于子类重写父类的抽象方法,用关键字implement来表示实现。实现接口方法的类叫做实现类。

  • 若实现类实现了接口的所有抽象方法,则实现类可实例化,否则实现类也必须为抽象类。
  • 对于重写父类的抽象方法,一般称之为实现,实现类实现接口的抽象方法,子类实现父类的抽象方法。
public class InterfaceTest {
	public static void main(String[] args) {
		Plane plane = new Plane();
		plane.fly();
	}
}

interface Flyable{
	public static final int MAX_SPEED = 7900;
	int MIN_SPEED = 1;
	
	public abstract void fly();
	void stop();
}

class Plane implements Flyable{

	@Override
	public void fly() {
		System.out.println("飞机起飞");
		
	}

	@Override
	public void stop() {
		System.out.println("驾驶员减速");
		
	}
	
}

接口的多实现

  • 一个类可以实现多个接口,那么类中就要实现多个接口的所有抽象方法。接口的多实现能弥补类的单继承问题。
  • 如果一个类同时存在继承和实现,先继承后实现。
  • 接口与接口之间也存在继承的关系,而且是多继承。
interface Flyable{
	public static final int MAX_SPEED = 7900;
	int MIN_SPEED = 1;
	
	public abstract void fly();
	void stop();
}

interface Attackable{
	void attack();
}

interface AA{
	void method1();
}

interface BB{
	void method2();
}

interface CC extends AA,BB{
	
}

class Bullet extends Object implements Flyable,Attackable,CC{

	@Override
	public void attack() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void fly() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void stop() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void method1() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void method2() {
		// TODO Auto-generated method stub
		
	}
	
}

接口的使用

接口使用的多态性

前面已经讲到,接口定义的是一种规范,它统一了方法的名称,实现了面向接口编程。下面讲讲规范的思想。
在这里插入图片描述

假如说电脑与打印机,U盘传输数据,都用的是USB接口,那么就定义interface USB,USB接口就成为了传输数据的一种规范。规范表现为就是多个不同实现类都共同使用的抽象方法的名称。

以上图为例,interface USB定义的全局常量看作是接口的长,宽,高,抽象方法看成是外设与电脑传输数据的功能,但具体功能的实现在外设内定义的,接口只起一个功能声明作用。

创建U盘,printer两个类,并实现USB接口的方法,形成实现类。在实现类中实现的方法可以看作是printer、U盘本身自带的驱动。电脑通过驱动程序传输数据,我们就理解为电脑类通过实现类重写的方法传输数据,接口在这儿起到了一个多态的作用,通过接口的多态性调用了实现类重写的方法。

具体代码如下

package com.atguigu.java1;

public class USBTest {
	public static void main(String[] args) {
		Computer computer = new Computer();
		Flash flash = new Flash();
		computer.transmit(flash);
	}
	
}

class Computer{
	public void transmit(USB usb){
		usb.start();
		System.out.println("正在传输");
		usb.end();
	}
}

interface USB{
	void start();
	void end();
}

class Flash implements USB{

	@Override
	public void start() {
		System.out.println("U盘传输开始");
		
	}

	@Override
	public void end() {
		System.out.println("U盘传输结束");
		
	}
	
}

class Printer implements USB{

	@Override
	public void start() {
		System.out.println("printer start");
		
	}

	@Override
	public void end() {
		System.out.println("printer end");
		
	}
	
}

运行结果为

U盘传输开始
正在传输
U盘传输结束

实际的方法体是写在实现类中的,类比这个例子,就好比是驱动程序写在U盘和printer内部,电脑在传输数据的时候,通过接口的多态性调用了U盘和printer内部的驱动。

如果不使用接口多态,当然也可以直接面向操作对象来编程,但缺点是
一是可能就会面临明明实现相同的功能,但功能名称却起得各不相同,不利于程序员编程。体现了接口的规范性。
二是直接面向对象编程,这样就可能得由开发者自己定义具体功能的实现,在有了接口以后,开发者只需调用接口,具体的功能实现则可以交给对象的厂商来负责。
在这里插入图片描述
java在调用数据库的时候,直接使用的是JDBC中定义的接口,而接口的具体方法实现,则交由数据库方面负责,数据库方面自己提供driver驱动程序。

项目的具体需求是多变的,接口就是以不变应万变来开发,这儿的不变指的就是接口(规范性)。面向接口(不变)优于直接面向对象(万变)。

匿名实现类

之前讲过非匿名子类的非匿名对象,非匿名子类的匿名对象,匿名子类的非匿名对象,匿名类的匿名对象
同理,实现类也具有类似的特征。

接口的非匿名实现类的非匿名对象

		Computer computer = new Computer();
		Flash flash = new Flash();
		computer.transmit(flash);

接口的非匿名实现类的匿名对象

		computer.transmit(new Printer());

Printer是实现类的名称,但对象是匿名的。

接口的匿名实现类的非匿名对象

		USB mp3 = new USB(){
			@Override
			public void start() {
				System.out.println("mp3传输开始");
				
			}

			@Override
			public void end() {
				System.out.println("mp3传输结束");
				
			}
		};
		computer.transmit(mp3);

PS:由于接口是没有构造器的,这儿的new USB() {} 不能看成是构造器,而是创建了一个实现类。

接口的匿名实现类的匿名对象

		computer.transmit(new USB(){
			@Override
			public void start() {
				System.out.println("phone传输开始");
				
			}

			@Override
			public void end() {
				System.out.println("phone传输结束");
				
			}
			
		});

jdk8的接口特性

JDK8及以后,接口内还可以定义静态方法和默认方法。

jdk8接口方法的调用

  • 静态方法和默认方法内都可以定义方法体。

首先在package中创建一个接口,接口可以用关键字public修饰

package com.atguigu.java8;

public interface CompareA {
	public static void method1(){
		System.out.println("CompareA :beijing");
	}
	
	public default void method2(){
		System.out.println("CompareA:shanghai");
	}
	
	default void method3(){
		System.out.println("CompareA:shanghai");
	}
}

注意,默认方法声明时可以不写public,但编译器会自动视作是带有public的。

接着创建一个SubClassTest的测试类

package com.atguigu.java8;

public class SubClassTest {

}

class SubClass implements CompareA{
	
}

此时编译器不会报错,因为静态方法和默认方法都有方法体。

  • 若类实现了接口,类中可以调用接口中的静态方法和默认方法
  • 调用接口中的静态方法,只能通过接口名调用
  • 调用接口中的默认方法,只能通过实现类的对象调用
package com.atguigu.java8;

public class SubClassTest {
	public static void main(String[] args) {
		CompareA.method1();
		SubClass s = new SubClass();
		s.method2();
		s.method3();
	}
}

class SubClass implements CompareA{
	
}

关于接口的运用,还可以用局部内部类实现接口java之内部类.

jdk8接口方法调用的优先级

假如说一个子类(实现类)既继承了父类,又实现了接口,在接口和父类以及子类中都有同名同参数的方法,那么调用该方法,优先级为子类重写的方法>父类的方法>接口的方法。

子类的方法看作是对父类方法和接口方法的重写,优先级最高

package com.atguigu.java8;

public class SubClassTest {
	public static void main(String[] args) {

		SubClass s = new SubClass();
		
		s.method3();
	}
}

class SubClass extends SuperClass implements CompareA{
	public void method3(){
		System.out.println("override");
	}
}

class SuperClass{
	public void method3(){
		System.out.println("SuperClass:beijing");
	}
}

运行结果为

override

jdk8接口方法调用的细节

1.一个类可以继承多个接口,若多个接口都有同名同参数的方法,此时要分为两种情况

(1). 若子类继承了父类 与接口 同名同参数的方法,编译器不报错,运行父类方法;若子类重写过 与接口 同名同参数的方法 ,运行子类重写的方法,总之,遵循上述调用的优先级。
(2). 若实现类中没有继承父类,也没有重写 接口 方法,编译器会报错,接口冲突,不允许多个接口有同名同参方法。

解决接口冲突,一般是在实现类中重写冲突的方法。

2.在子类(实现类)、父类、接口中出现了同名同参数方法,又想调用父类或接口中的方法,也是有办法的。

  • 调用父类就用 super.
  • 调用接口方法就用 接口名.super.方法名();
class SubClass extends SuperClass implements CompareA{
	public void method3(){
		System.out.println("override");
	}
	
	public void myMethod(){
		method3();
		super.method3();
		CompareA.super.method3();
	}
}

运行结果为

override
SuperClass:beijing
CompareA:shanghai

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值