【Java】接口详解-《Java核心技术 卷Ⅰ》

一、引例

我们知道,Arrays.sort()方法可以对一个数组进行排序。如果是一个自定义的类,想要使用sort方法,编译器该如何比较自定义类的大小并将数组进行排序呢?
sort方法中存在一条这样的语句:

if(a[i].compareTo(a[j]) > 0)
{
   ...
}

Java是一种强类型语言,在调用一个方法时,编译器必须要先确认该方法确实存在。
对应此例,在使用sort方法时,必须确保compareTo方法存在。
因此,Java的设计者们想出这样一个办法:设计一个Comparable接口,里面定义了一个compareTo方法。如果你想要使用sort方法去排序自定义的类,该类必须实现(implement) Comparable方法并覆盖其中的compareTo方法。

public interface Comparable<T>//接口,放在package interfaces中
{
   int compareTo(T other);
}

public class Employee implements Comparable<Employee>//自定义Employee类实现接口
{  
   ...
   public int compareTo(Employee other)//实现接口中定义的方法
   {
      return Double.compare(salary, other.salary);
   }
   ...
}

var staff = new Employee[3];
...//省略数组的初始化
 Arrays.sort(staff);//合法

二、接口的特性

接口不是类,但可以将其与没有实例字段的抽象类做出类比。
1、接口中的所有方法自动声明为public,因此接口中的方法不用在使用public关键字。但在类中实现接口中定义的方法时,需要声明为public。(允许将方法定义为private或public static,但几乎不使用
2、接口中绝对不可能出现实例字段,但允许出现常量。常量被自动声明为public static final。

public interface Moveable
{
   double move();//自动声明为public
   double SPEED_LIMIT = 95;//自动声明为public static final
}

3、接口中允许实现简单的方法(标题三中会详细介绍)。
4、接口不是类,因此不允许使用new运算符实现一个接口。但是,允许声明接口的一个变量,该变量必须引用实现了这个接口的类的对象。

// 接上例
Comparable x;
x = new Employee(...);//接口变量引用实现接口的类的对象

5、接口与接口之间,允许存在扩展关系(extends)

// 接上例,Powered接口继承Movable
public interface Powered extends Moveable
{
   double milesPerGallon();//自动声明为public
   //Powered接口现在有两个方法及一个常量
}

6、一个类只允许继承一个超类,但可以实现多个接口。这也是接口区别于类的最大特性。(一个类既继承超类又实现接口时,extends应位于implements之前

class Employee extends Person implements Moveable, Comparable
{
   ...
}

三、接口中的默认方法

1、默认(default)方法的作用:“接口演化”。
假定很早之前你实现了一个Bag类,

public class Bag implements Collection

但随着Java更新,Collection接口在Java 8中增加了一个stream方法。如果不做任何处理,由于原先你写的Bag类中没有实现stream方法,也没有声明为static,就会编译出错。
因此,Java设计者们为了保证“源代码兼容”,将新增的stream方法声明为default,并提供一个默认实现。这样,Bag类就可以正常加载了,并且,当在Bag的一个实例上调用stream方法时,会正常调用Collection.stream方法。
2、默认方法举例:Collection接口

public interface Collection
{
   int size();
   default boolean isEmpty() { return size() == 0;}
   //默认方法允许调用其他方法
}

四、解决继承超类与实现接口中的方法冲突

情况一:接口与接口间的冲突
假定有如下两个接口,它们具有同名的方法,并且至少有一个对该方法进行了默认实现。
此时一个Student类同时实现这两个接口。

public interface Person
{
   default String getName(){return "";}
}
public interface Named
{
   default String getName(){return getclass().getName();}
}

class Student implements Person, Named{...}//产生冲突,编译器不知道该使用哪一个getName方法。
//正确做法:类中需要覆盖getName方法
class Student implements Person, Named
{
   public String getName(){return Person.super.getName();}
}//这样编译器会执行Person中的getName方法

如果接口中同名方法均未有默认实现,则不存在冲突。
情况二:接口与超类间的冲突
将上例中的interface Person改写为 class Person,则不会产生冲突,编译器默认超类方法优先于接口中的默认方法。

public class Person
{
   default String getName(){return "";}
}
public interface Named
{
   default String getName(){return getclass().getName();}
}

class Student extends Person implements Named{...}//不产生冲突,调用Person中的getName方法
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值