接口
- java中还有一种特殊的抽象类叫做接口
引入
- java有一种特殊的抽象类叫做接口,我们可以创建一个接口用来管理子类,使用子类实现该接口,如下方代码所示创建一个Animal接口:
- 在接口中方法要为抽象方法,否则会报错,除非版本大于java8.0,可以用default和static修饰的方法
- 在接口中只能使用public abstract来声明方法,而且因为只有一种写法public和abstract是可以省略的
- 接口自带public static final修饰变量,自带public abstract 修饰方法
- 接口可以继承其他接口 ,且为多继承(弥补了在java中类不能多继承的功能缺失)
- 接口类中的静态方法和普通的类不同,静态方法不但在物理空间上始终属于接口,且只能通过接口类名访问,这是为了避免接口多继承导致的钻石继承问题
package com.inter; //public class Animal { public interface Animal { //使用interface关键字替代class创建接口 //因为在接口中会将方法默认指定为public和abstract,哪怕不写也是一样的 // private void sleep();//接口中只允许将对象设置为public void sleep(); // int a = 1; //实际上在接口中的成员变量默认为 public static final int a = 1;//但实际上也可以只写为int a = 1;省略public static final //因为变量被final修饰过所以必须要对变量进行初始化,因为用了static修饰,所以在AnimalTest的mian方法中可以直接使Aanmal.a拿到Animal类中的a的值 void eat(); //在java8之后接口内也可以定义普通方法,使用default修饰符或者Static修饰符就行 default void game(){ test(); System.out.println("狗子在玩"); } static void run(){ System.out.println("狗子在跑"); } // java9之后使用private也是被允许的 private void test(){ System.out.println("测试private"); } //因为使用private进行修饰,所以只能在接口Animal类中调用 } - 使用Dog类和Cat类来实现接口,这里我们使用关键字
implements+接口名来表示该类是用于实现哪个接口的,实际上,实现接口也是一种特殊的继承
// Dog
package com.inter;
public class Dog implements Animal{
@Override
public void sleep() {
System.out.println("狗子在睡觉");
}//当实现接口的类是空的时候,光标留在类名处按下键盘的“alt + enter” ,ide会帮我们弹出对话框,里面有要实现的抽象方法
@Override
public void eat() {
System.out.println("狗子吃骨头");
}
}
- AnimalTest类作为测试用例:
package com.inter;
public class AnimalTest {
public static void main(String[] args){
int a = Animal.a;//不用创建对象就可以访问成员变量a
// Animal animal = new Animal();
//不能创建对象,因为Animal为接口,接口的本质为抽象类,而抽象类是不能被实例化的
//想要使用接口就必须用类来实现它,下面我们创建一个Dog类来实现接口
Dog dog = new Dog();
dog.eat();
dog.sleep();
//要使用接口中的普通方法,只能通过类名,或者说是接口名进行访
dog.game(); //implements实现接口就相当于继承了接口的内容
// dog.run();//发现访问失败,虽然dog相当于Animal的子类但run使用的static修饰的
Animal.run();
}
}
接口的继承
- 接口也是可以继承的,创建一个Atest类,继承自Animal
package com.inter;
public interface Atest extends Animal{
//接口的继承例子
void OnTest();
void Onclick();
}
- 写一个Atest的测试用例类,AtestGet.java,我们发现java会强制我们实现接口Atest和其继承的接口Animal,如下方代码所示:
package com.inter;
public class AtestGet implements Atest{
@Override
public void OnTest() {
}
@Override
public void Onclick() {
}
@Override
public void sleep() {
}
//继承于Animal接口的实现的抽象方法
@Override
public void eat() {
}
@Override
public void game() {
Atest.super.game();
}
}
接口的多继承
- 虽然java是单继承语言,但是java的接口是可以多继承的,比如这里我简单写两个接口,注意这两个接口中我使用了同名的方法,在Java8之后为了方便实现的类选择具体实现哪个接口的方法,需要使用default参数修饰接口中同名的方法
//接口A
public interface InterfaceA {
default void commonMethod() {
System.out.println("InterfaceA 的 commonMethod");
}
}
//接口B
public interface InterfaceB {
default void commonMethod() {
System.out.println("InterfaceB 的 commonMethod");
}
}
- 一个类可以实现多个接口,当接口类中方法的名字冲突时,使用
interFaceName.super.functionName()来选择具体是哪个接口的方法:
public class MyClass implements InterfaceA, InterfaceB {
@Override
public void commonMethod() {
// 选择调用 InterfaceA 的默认方法
InterfaceA.super.commonMethod();
// 添加自己的具体实现
System.out.println("Test");
}
public static void main(String[] args) {
MyClass myClass = new MyClass();
myClass.commonMethod();
}
}
运行输出示例:
InterfaceA 的 commonMethod
Test
- 当然如果多继承的接口中有同名的抽象方法,当原型相同时,只需要实现一个抽象方法
public interface InterfaceA {
void commonMethod();
}
public interface InterfaceB {
void commonMethod();
}
public class MyClass implements InterfaceA, InterfaceB {
@Override
public void commonMethod() {
// 只需要实现一次!
System.out.println("同时满足两个接口的要求");
}
}
- 当然如果多继承的接口中有同名的抽象方法,当原型不相同时,要在实现类中重载实现抽象方法:
public interface InterfaceA {
void commonMethod(String s); // 参数是 String
}
public interface InterfaceB {
void commonMethod(int i); // 参数是 int
}
public class MyClass implements InterfaceA, InterfaceB {
@Override
public void commonMethod(String s) {
System.out.println("String版本: " + s);
}
@Override
public void commonMethod(int i) {
System.out.println("int版本: " + i);
}
public static void main(String[] args) {
MyClass m = new MyClass();
m.commonMethod("hello"); // 调用 String 版本
m.commonMethod(100); // 调用 int 版本
}
}
总结
-
虽然在ide中接口文件是没有后缀的,但是打开资源管理器查看可以发现其实接口还是java文件
-
接口实际上相当于特殊的抽象类,所以不能实例化
-
在接口中只能使用
public abstract来声明方法,而且因为只有一种写法所以public abstract是可以省略的,只要在抽象类中创建方法默认就是public abstract -
接口自带public static final修饰变量,自带public abstract 修饰方法
-
在接口中方法要为抽象方法,否则会报错,除非版本大于java8.0,才可以用default和static修饰的方法
-
在实现类中使用
implements interName实现接口,实际上这也是一种特殊的继承 -
接口可以继承其他接口
- 接口支持多继承,一般的抽象方法,如果重名会同时实现一套方法,在java8之后提供了default修饰的方法,在是现时可以选择要实现哪个接口中的同名方法,通过
interFaceName.super.functionName()
- 接口支持多继承,一般的抽象方法,如果重名会同时实现一套方法,在java8之后提供了default修饰的方法,在是现时可以选择要实现哪个接口中的同名方法,通过
-
接口不能实现其他接口
-
当类实现接口时,如果有抽象方法没有被实现,ide会报错提示我们实现该方法,我们只需要按下alt+enter就可以在实现接口的类中写入该方法的方法体:
接口与抽象类对比
联系
- 抽象化: 无论是抽象类还是接口,都可以包含抽象方法,即没有方法体的方法。这些方法需要在子类或实现类中具体实现。
- 多态: 通过抽象类或接口,可以实现多态性,允许父类引用变量持有子类对象,从而实现方法的动态绑定。
- 封装:它们都可以帮助实现良好的封装,隐藏对象的具体实现细节,只暴露公共接口给外部使用。
不同
-
定义方式:
- 抽象类使用
abstract class关键字定义 - 接口使用
interface关键字定义。
- 抽象类使用
-
继承方式:
-
由于java是单继承语言,一个类只能继承一个抽象类,但可以实现多个接口。
-
抽象类可以有构造器,而接口不能有构造器。
-
抽象类中可以有实例变量,而接口中所有的属性默认都是
public static final,即常量- 这里要注意的是虽然抽象类没有办法被实例化,但是其变量是可以被子类继承的,而默认变量(public static final)则都是静态变量,属于接口类,不能被子类(实现接口的类)继承,只能是通过子类对象访问。
-
总的来说,抽象类可以给子类可继承的普通变量和方法,而接口则不行
-
-
方法实现:
- 抽象类可以包含非抽象方法(即已经实现了的方法),也可以包含抽象方法。
- 接口中所有方法默认都是
public且abstract的,从Java 8开始,接口还可以包含默认方法(default)和静态方法(static),这使得接口中的方法可以有具体的实现。
-
使用场景:
-
抽象类:
- 当几个相关的类共享了相同的代码时,可以将这些共有的部分提取到一个抽象类中。
- 当想要保护某些方法不被子类重写时,可以在抽象类中定义这些方法为
final。
-
接口:
- 当需要定义一个类型,该类型具有特定的行为但不关心实现细节时,可以使用接口。
- 当需要实现多重继承的效果时,由于Java不支持多继承,所以可以通过实现多个接口来达到类似的目的。
- 当希望强制要求一些类实现一组特定的方法时,可以定义一个接口让这些类去实现。
-
接口的应用
- 除了实例化实现接口的类以外
- 还可以在普通类中先声明接口,在设计构造函数强制传入实现接口的类的对象,在普通类示例化的时候,普通类实例化对象,接口的声明即会更具情况持有不同的接口实现类的对象(多态),在使用接口的引用去调用方法,具体用法请看查看泛型在接口的应用