在之前的博客中,我有写到接口,但是还有一些语法没有总结到。本篇博客旨在于将接口拎出来单独总结。
接口从某种意义上来说,就是完完全全的抽象类。
接口:由 interface 实现,如:
interface IA {
}
① 接口中的普通方法,不能有具体实现,如果非要实现,需要被 default 修饰这个方法
② 接口中的所有方法的限定符都是 public,那么所有的方法都可以省略 public,而接口中的所有抽象方法的限定符都是 abstract public,那么所有的抽象方法同样可以省略 abstract public
③ 接口中的成员变量默认是被 public static final 修饰的,也就是说,接口中的成员变量必须被初始化
④ 接口不可以通过 new 实例化对象
⑤ 如果一个类实现了一个接口,那么在这个类中,必须重写接口中所有的抽象方法,而且重写的抽象方法必须被 public 修饰(因为接口中的抽象方法默认是 public abstract)
⑥ 如果一个类 A 实现了接口 B,那么对应的代码格式为:
interface IB{
}
class A implements IB{
}
⑦ 一个类可以实现多个接口,然而一个类只能继承一个类
interface IX{
}
interface IY{
}
class Z{
}
class A extends Z implements IX,IY{
}
⑧ 两个接口之间使用 extends,表示一个接口拓展另一个接口。
注意下面代码,当类 A 实现了接口 IY ,类 A 必须重写两个方法。
interface IX{
void func1();
}
interface IY extends IX{
void func2();
}
class A implements IY{
@Override
public void func2() {
}
@Override
public void func1() {
}
}
在程序清单1中,我通过注释标明了接口使用时的一些语法规则,这十分重要!
程序清单1:
interface IShape{
public int a; //error
public static final int b = 10; //right
int c = 20; //right
public void func1(){ //error
}
default public void func2(){ //right
}
public static void write(){ //right
}
abstract public void draw1(){ //error
}
abstract public void draw2(); //right
void draw3(); //right
}
public class Test {
public static void main(String[] args) {
IShape iShape = new IShape(); //error
}
}
程序清单2:
class Animal{
String name;
public Animal(String name) {
this.name = name;
}
public void eat(){
System.out.println(name + " 正在吃东西");
}
}
interface IFlying{
void fly();
}
class Bird extends Animal implements IFlying{
public Bird(String name) {
super(name);
}
//重写了接口中的方法
@Override
public void fly() {
System.out.println(name + " 正在飞");
}
//重写了父类中的方法
@Override
public void eat() {
System.out.println(name + " 正在喝蜂蜜");
}
}
public class Test {
public static void fly(IFlying iFlying){
iFlying.fly();
}
public static void main(String[] args) {
fly(new Bird("老鹰"));
new Bird("蜜蜂").eat();
}
}
输出结果:
对程序清单2 进行分析:
在程序清单2 中,我们演示了继承和接口,有几个语法点很关键:
① 在父类构造带参数的方法的同时,子类也需要构造同样的带参数方法。
public Bird(String name) {
}
② 在父类已有的普通成员方法情况下,子类却重写了父类的此方法,那么在编译时,系统直接使用子类重写的方法。
public void eat(){
}
③ 接口中的抽象方法是被 abstract public 修饰的,那么在一个类实现接口的时候,我们就必须对此抽象方法进行重写。
@Override
public void fly() {
System.out.println(name + " 正在飞");
}
通常情况下,一个类实现了另一个接口,我们只能使用 implements 显示地表现出来,如下面的程序:
程序清单3:
interface IA{
void test();
}
class B implements IA {
@Override
public void test() {
System.out.println("我通过类 B 重写了接口的 test 方法");
}
}
public class Test {
public static void main(String[] args) {
B b = new B();
b.test();
}
}
输出结果:
而我们知道接口是不能通过 new 来实例化对象的,但有时候我们也会看到【 new 接口 】的情况出现,但不会被编译器报错。因为这是一个匿名内部类实现接口的缘故,只是这个匿名类看起来被隐藏了一样,给人一种 new 了一个接口的错觉,而实际上匿名内部类实现了另一个接口,那么它依然需要重写接口中的抽象方法。所以,一个接口依然不能通过 new 实例化对象!
//语法格式
new + 接口名 + {
//这里必须重写接口中的抽象方法!
};
通过下列程序来进行演示为什么可以这么做:
程序清单4:
interface IA{
void test();
}
public class Test {
public static void main(String[] args) {
IA ia = new IA(){ //1
@Override
public void test() { //2
System.out.println("我匿名重写了接口的 test 方法");
}
};
ia.test();//3
}
}
//注释
//1. 匿名类实现了接口 IA
//2. 匿名类重写了 test 方法
//3. 匿名类调用了 test 方法
输出结果:
程序清单4 又可以简化成程序清单5
程序清单5:
interface IA{
void test();
}
public class Test1 {
public static void main(String[] args) {
new IA(){ //1
@Override
public void test() { //2
System.out.println("我匿名重写了接口的 test 方法");
}
}.test(); //3
}
}
//注释
//1. 匿名类实现了接口 IA
//2. 匿名类重写了 test 方法
//3. 匿名类调用了 test 方法
输出结果:
而程序清单5 又可以写成 Lambda 表达式
( (IA) () -> { System.out.println("我匿名重写了接口的 test 方法");} ).test();