接口
- 概念:接口是一种特殊的抽象类,通常用于定义标准或标注额外能力。
演示的代码如下:
package com.txw.test;
public class TestInterface{
public static void main(String[]args){
// USB 标准 对象与对象之间的一种链接方式
// TYPE-C 标准
MyClass mc; // 可以声明引用
// mc = new MyClass(); // Error 不能创建对象
mc = new Sub(); // 使用多态
MyClass.m3(); // 调用静态方法
}
}
// 抽象类
abstract class MyClass{
int a; // 属性
static int b; // 静态属性
final static int C = 10; // 静态常量
public MyClass(){} // 构造方法
public void m1(){} // 普通方法
public abstract void m2(); // 抽象方法
public static void m3(){}; // 静态方法
}
// 子类继承父类
class Sub extends MyClass{
// 实现父类中的抽象方法
public void m2(){
}
}
1 语法
1.1 定义接口
- 语法如下:
演示的代码如下:interface 接口名{ }
interface MyInterface{ }
1.2 接口与抽象类的异同
演示的代码如下:
package com.txw.test;
public class TestInterface2{
public static void main(String[]args){
// USB 标准 对象与对象之间的一种链接方式
// TYPE-C 标准
MyInterface mi;
mi = new Sub(); // 使用多态
MyInterface.m1(); // 调用静态方法
System.out.println( MyInterface.MY_VALUE );
// MyInterface.MY_VALUE2 = 300;
System.out.println( MyInterface.MY_VALUE2);
}
}
// 接口
interface MyInterface{
// 公开静态常量
public static final int MY_VALUE = 100;
int MY_VALUE2 = 200; // 隐式包含 public static final
// 静态方法
static void m1(){
}
// 接口中的普通方法,必须使用default
public default void m2(){
}
//公开抽象方法
public abstract void m3();
void m4(); // 隐式包含 public abstract
}
// 子类实现接口
// class Sub implements MyInterface{
//}
-
相同点:
- 只能声明引用,不能创建对象。
演示的代码如下:
MyInterface mi; mi = new MyInterface(); // Error
2)可以使用多态。
演示的代码如下:MyInterface mi; mi = new MyClass();
3)都可以定义静态方法(JDK8)。
演示的代码如下:// 接口 interface MyInterface{ // 静态方法 public static void m1(){ } }
4)都可以定义一般方法,接口中要使用
default(非访问权限修饰符)
进行修饰(JDK8)。
演示的代码如下:// 接口 interface MyInterface{ // 静态方法 static void m1(){ } // 接口中的普通方法,必须使用default public default void m2(){ } }
1.3 不同点
- 只能声明引用,不能创建对象。
-
接口中的属性默认为公开静态常量。
演示的代码如下:interface MyInterface{ // 公开静态常量 public static final int MY_VALUE = 100; int MY_VALUE2 = 200; // 隐式包含 public static final }
-
接口中的方法默认为公开抽象方法。
演示的代码如下:// 接口 interface MyInterface{ // 公开抽象方法 public abstract void m3(); void m4(); // 隐式包含 public abstract }
由于接口中的方法默认包含public abstract,所以如果定义一般方法,必须加入default修饰符用于区分。
-
接口中不能定义构造方法。
2 接口的使用方式
2.1 实现接口
- 作用:接口必须依赖类继承(实现)后通过多态才能使用。
- 实现接口的语法如下:
class 类名 implements 接口名{ }
演示的代码如下:
interface Super{
}
// Sub实现Super接口
class Sub implements Super{
}
Super也会称为Sub的一种父类型,具有继承的效果,从父类中继承属性或方法。
-
如果接口中有抽象方法,子类不想成为抽象类则必须实现接口中的所有抽象方法。
演示的代码如下:interface Super{ void m1(); } // 未实现Super类中的抽象方法,那么子类还是抽象类 abstract class Sub1 implements Super{} // 实现Super类中的所有抽象方法,子类可以不是抽象类 class Sub2 implements Super{ // 实现接口中的抽象方法 public void m1(){ } }
2.2 创建对象,配合多态
- 演示的代码如下:
为了更好区分类与接口,类与类之间的关系称为继承,类与接口之间的关系称为实现,接口的子类称为实现类。Super sup; // 接口 sup = new Sub(); // 子类对象 sup.m1(); // 调用方法
3 关系
3.1 接口与接口之间可以多继承
- 演示的代码如下:
interface IA{ public void m1(); } interface IB { public void m2(); } // 接口与接口之间可以继承 // 接口与接口之间可以多继承 interface IC extends IA,IB{ //I A: m1(); //I B: m2(); }
3.2接口与类之间可以多实现
演示的代码如下:
interface IA{
public void m1();
}
interface IB {
public void m2();
}
// 接口与类多实现
class MyClass implements IA,IB{
// IA: m1();
public void m1(){}
// IB: m2();
public void m2(){}
}
3.3 类可以继承另外一个类并实现多个接口
演示的代码如下:
class Super{}
// MyClass继承Super并实现IA,IB接口
// 接口与类多实现
class MyClass extends Super implements IC,ID{
//I A: m1();
public void m1(){}
//I B: m2();
public void m2(){}
}
4 接口的作用【了解】
4.1 标注一个类所具备的额外能力
- 作用:可以根据一个类所具备的能力筛选对象,更贴近现实可以更灵活的使用多态。
演示的代码如下:// 动物数组 Animal[] as = {new Dog(),new Cat(),new Bird(),new Fish(),new Cat(),new Bird(),new Dog(),new Fish()}; // 请找出所有会跑的动物 for(int i=0; i<as.length; i++){ // 提取数组中的一种动物 Animal a = as[i]; if( a instanceof Runnable ){ // 将a引用中的对象存储到Runnable引用里,由于可能失败需要强转 Runnable r = (Runnable)a; // 调用run方法 r.run(); } }
4.2 标记型接口,用于授权
- 作用:向其他类证明自己所具备的一些特点(特权)。
演示的代码如下:public interface Serializable {} // 可序列化接口 public interface Cloneable {} // 可克隆接口
4.3 使用接口更好的降低耦合
- 耦合度:表示对象与对象的关联性,关联性强(依赖性强) 则耦合度高扩展性差。
演示的代码如下:package classes; public class TestInterface{ public static void main(String[]args){ USB mouse = new Mouse(); // 鼠标 USB key = new Keyboard(); // 键盘 USB fan = new Fan(); // 风扇 USB hum = new Humidifier(); // 加湿器 Computer com = new Computer(); com.setUSB1( fan ); //com.setComputerEquipment1( key ); // 接入鼠标 插入第一个接口 //com.setComputerEquipment2( mouse ); // 接入键盘 插入第二个接口 com.on(); } } // USB协议 interface USB{ public void service(); } class Computer{ // 插口 USB usb1; USB usb2; public void setUSB1(USB usb1){ // 插入鼠标 this.usb1 = usb1; } public void setUSB2(USB usb2){ // 插入键盘 this.usb2 = usb2; } // 开机 public void on(){ System.out.println("电脑开机"); if(usb1!=null) usb1.service(); // 鼠标提供服务 if(usb2!=null) usb2.service(); // 键盘提供服务 } } class Fan implements USB{ // 电风扇 public void service(){ System.out.println("吹~~~~"); } } class Humidifier implements USB{ // 加湿器 public void service(){ System.out.println("降低干燥度"); } } class ComputerEquipment{ // 电脑外设 public void service(){} } class Mouse extends ComputerEquipment implements USB{ // 鼠标 public void service(){ System.out.println("控制指针移动"); } } class Keyboard extends ComputerEquipment implements USB{ // 键盘 public void service(){ System.out.println("输入信息 "); } }
4.4 更好的管理常量
- 因为接口中所有的属性默认为公开静态常量,所以使用接口便于管理常量。
演示的代码如下:interface Color{ // 颜色 int RED = 1; int GREEN = 2; int YELLOW = 3; }
4.5 函数式接口
- JDK8配合Lambda表达式与 流式编程一起使用的手段。
演示的代码如下:
函数式接口声明时会使用@FuncationalInterface注解,内部只有一个抽象方法。@FunctionalInterface public interface Consumer<T> { void accept(T t); // 略 }
5 习题
- 关于接口和抽象类,下列说法正确的是(A C D)。
A. 抽象类可以有构造方法,接口没有构造方法。
B. 抽象类可以有属性,接口没有属性。
C. 抽象类可以有非抽象方法,接口中都是抽象方法。
D. 抽象类和接口都不能单独创建对象。 - 下列哪一种叙述是正确的( C)。
A. 一个 Java 类只能实现一个接口。
B. 一个 Java 类不能同时继承一个类和实现一个接口。
C. 一个 Java 类可以实现多个接口。
D. 一个 Java 类只能直接继承一个类。 - 仔细阅读以下代码,有几处错误代码?并修改正确。
答:
interface IA {
void m1();
int a = 100;
}
class MyClass implements IA{
public void m1() { } // 接口中方法默认是public的,因此实现类必须也是public的
}
public class TestInterface{
public static void main(String[] args) {
IA ia = new MyClass();
ia.m1();
System.out.println(ia.a);
}
}
- 仔细阅读以下代码,根据语法将代码补全。
答:
interface IA{
void m1();
void m2();
}
abstract class MyClassAimplements IA{
public void m1(){}
}
class MyClassB extends MyClassA{
public void m2() {}
}
- 仔细阅读以下代码,根据要求完成程序。
(1) 如果有一个类 ClassE 实现 ID 接口,如果不希望 ClassE 是抽象的,则需要实现哪些方法?
(2) 将以下代码补充完整。
(3) 写出以下程序输出的结果。
答:
I. 要实现 ma,mb,mc,md 方法
II. 调用 mc 方法时不用强转,调用 ma/mb/md 方法时需要强转 I
II. 输出为 5 个 true。 - 仔细阅读以下代码,写出程序输出的结果。
答:输出结果为 4 个 true。
原因: 如果父类实现了某些接口,则子类自动就实现了这些接口。 - 仔细阅读以下代码,写出程序运行输出结果。
答:
输出结果
Red Light shine in Red
Yellow Light shine in Yellow
Green Light shine in Green
注:多态中方法有覆盖,执行的是覆盖之后的。 - 仔细阅读以下代码,写出程序输出的结果。
答:输出结果
TeacherAteach Java
TeacherBteach Java
解释:本题的重点在于利用接口,把多态用在返回值类型上。getTeacher方法返回的对象是 JavaTeacher 接口类型,在 getTeacher 方法内部创建 JavaTeacher 实现类的对象,并作为返回值返回。
注意:对于 getTeacher 的调用者而言,不需要关心 JavaTeacher 的实现类,而只要操作 JavaTeacher接口,从而 实现了弱耦合。 - 仔细阅读以下代码:
需要一个实现 ServiceInterface 接口的类 MyService。
(1) 第一种方式可以让 MyService 实现 ServiceInterface 接口,即: class MyService implements ServiceInterface (2) 第二种方式可以让 MyService 继承 AbstractService 类,即: class MyService extends AbstractService
请问:这两种方式有什么区别?AbstractService 类有什么作用?
答:
如果实现 ServiceImpl 接口,则必须实现其所有方法。而如果继承 AbstractService 类,则只需要覆盖其中我们感 兴趣的方法即可。在实际开发中,往往既提供接口,又提供抽象类。既可以提供接口灵活性的基础,也能够使用抽象类来减 少代码量。 - 仔细阅读以下代码,完成//1、//2、//3、//4 处程序。
答:
//1 处填入的代码为 Animal[] as = { new Dog(),new Cat(),new Wolf() };
//2 处填入的代码为 for (int i = 0;i<as.length; i++){ as[i].eat(); }
//3 4 处填入的代码为 int count = 0; for (int i = 0;i<as.length; i++){ if(as[i] instanceof Pet){ count++; Pet p = (Pet) as[i]; p.play(); }}System.out.println(count); - 编程:定义一个接口 MathTool,接口中有三个抽象方法如下:
(1) “long fact(int m);”方法的功能为:求参数的阶乘。
(2) “long intPower(int m , int n)”方法的功能为:求 m 的 n 次方。
(3) “boolean findFactor(int m,int n)”方法的功能为:判断参数的和是否大于 100 定义类实现接口,编写应用程序,调用接口中的 3 个方法,并将调用方法的结果输出。
演示的代码如下:
package com.txw.test;
public class Test {
public static void main(String[] args) {
MathTool m = new TestMathTool();
System.out.println(m.fact(5));
System.out.println(m.intPower(2, 3));
System.out.println(m.findFactor(1, 1));
}
}
interface MathTool {
// 求阶乘
public abstract long fact(int m);
// 求m的n次方、
public abstract long intPower(int m, int n);
public abstract long findFactor(int m, int n);
}
class TestMathTool implements MathTool {
@Override
public long fact(int m) {
long result = 1;
for (int i = 2; i <= m; i ++) {
result *= i;
}
return result;
}
@Override
public long intPower(int m, int n) {
long result = 1;
for (int i = n; i > 0; i --) {
result *= m;
}
return result;
}
@Override
public long findFactor(int m, int n) {
return 0;
}
}
- 编程:验证歌德巴赫猜想:输入一个大于 6 的偶数,请输出这个偶数能被分解为哪两个质数的和。 如 10=3+7 12=5+7 要求:两个人一组合作完成。一个人负责把一个整数 n 拆分成两个整数的和,另一个人负责写一个函 数,判断某一个整数 a 是否是质数 。
演示的代码如下:
package com.txw.test;
import java.util.Scanner;
interface MathTool{
boolean isPrime(int n);
}
// 接口实现者
class MathToolImpl implements MathTool{
public boolean isPrime(int n) {
for(int i = 2; i<= Math.sqrt(n); i++){
if (n % i == 0)
return false;
}return true;
}
}
// 接口的使用者
public class TestGoldBach {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
MathTool mt = new MathToolImpl();
for(int i = 2; i<=n/2; i++){
if (mt.isPrime(i) && mt.isPrime(n - i)){
System.out.println(n + "=" + i + "+" + (n - i));
}
}
}
}
6 总结:接口与抽象类的区别
类 | 抽象类 | 接口 | |
---|---|---|---|
属性 | 无要求 | 无要求 | 默认为公开静态常量 隐式包含:public static final |
一般方法 | 静态|非静态 | 静态|非静态 | 静态|非静态需要使用default修饰 |
构造方法 | 有 | 有 | 无 |
抽象方法 | 无 | 可有可无 | 默认为公开抽象方法 隐式包含:public abstract |
继承关系 | 单继承 | 单继承 | 接口与接口多继承,类与接口多实现 |
关键字 | class | abstract class | interface |
如图所示: