一、接口(Interface)
1.1 接口的概念
- 接口不是类,而是符合这个接口的类的
一组需求
。 - 接口中的所有方法都自动是 public 方法。因此,在接 声明方法时,不必提供关键字 public
- 接口没有实例字段,因为接口
不是类
(没有实例) - 接口实现 使用
implements
下面展示 接口的例子
。
package Interfaces;
public class Employee implements Comparable<Employee>{
private String name;
private double salary;
public Employee(String name, double salary)
{
this.name = name;
this.salary = salary;
}
public String getName()
{
return name;
}
public double getSalary()
{
return salary;
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
@Override
public int compareTo(Employee o) {
return Double.compare(salary, o.salary);
}
}
package Interfaces;
import java.util.*;
public class EmployeeSortTest {
public static void main(String[] args) {
var staff = new Employee[3];
staff[0] = new Employee("Harry Hacker", 35000);
staff[1] = new Employee("Carl Cracker", 75000);
staff[2] = new Employee("Tony Tester", 30000);
Arrays.sort(staff);
for (Employee e : staff)
System.out.println("name = " + e.getName() + ",salary=" + e.getName());
}
}
现在,我们已经看到,要让一个类使用排序服务必须让它实现 compareTo
方法。这是理所
当然的,因为要向 sort
方法提供对象的比较方式。但是为什么不能在 Employee 类中直接提供一个 compareTo 方法 (而不实现 Comparable 接口) 呢?
因为java是一种强类型语言,调用方法时,编译器要检查这个方法必须存在,在sort方法中可能含有以下语句:
if(a[i].compaareTo(a[i])>0)
{
//rerange a[i] and a[j]
.....
}
编译器必须确认已a[i] 一定有一个 compareTo 方法.如果 a 是一个 Comparable 对象的数组,
就可以确保肯定有 compareTo 方法,因为每个实现 Comparable接口的类都必须提供这个方法.
注释
:你可能认为,如果将 Arrays 类中的 sort 方法定义为接受一个 Comparable 数组,
倘若有人调用 sort 方法时所提供数组的元素 类型没有实现 Comparable 接口,编译器就
能报错。 遗憾的是,事 实并非如此占 实际上,sort 方法接受一个 Object[] 数组,并使
用一个笨拙的强制类型转换:
if(((Comparable) a[i]).compareTo(a[j])>0)
{
// rearrange a[i] and a[j]
}
如果使用 不属于一个实现了 Comparable 接口的类,虚拟机就会抛出一个异常,,
1.2 接口的属性
- 接口不是类 不能用
new
实例化
x = new Comparable(...)
- 可以声明接口变量,并且必须引用实现了这个接口的一个类对象
Comparable x;
x = new Employee(...); //provided Employee impolements Comparable
- 可以使用
instanceof
检查一个对象是否属于某个特定类一样,也可以使用instanceof 检查一个对象是否实现了某个特定的接口:
if (anObject instanceof Comparable){
... }
- 扩展接口
public interface Moveable
{
void move(double x, double y);
}
使用extends
关键字扩展以上接口:
public interface Powered extends Moveable
{
double milesPerGallon();
}
- 接口不包含实例字段,但是可以包含常量, 方法自动为
public
,类似的,接口的字段自动为public static final
public interface Powered extends Moveable
{
double milesPerGallon();
double SPEED_LIMIT = 95; // a public static final constant
}
- 可以实现多个接口
- 接口也可以是密封的直接子类型(可以是类或接口)必须在
permits
子句中声明,或者要放在同一个源文件中。
1.3 接口和抽象类
区别
每个类可以实现任意多个接口, 但只能扩展一个抽象类。
1.4 静态方法和私有方法
在 Java 9中,接口中的方法可以是 private 方法。private 方法可以是静态方法或实例方法。由于私有方法只能在接口本身的方法中使用,所以它们的用途很有限,只是作为接口中其他方法的辅助
1.5 默认方法
default
就是类不用实现该方法,就可以使用。
public interface Comparable<T>
{
default int compareTo(T other){
return 0}
}
一个重要用法就是接口演化
例如,很久以前提供了这样一个Bag
类
public class Bag implements Conllection
后来,在 java8 中增加一个 stream 方法,那么 Bag 类就不能编译,因为它没有实现这个新方法,为接口增加一个非默认方法,不能保证源代码兼容
将方法实现为一个默认 ( default) 方法就可以解决这两个问题。Bag 类又能正常编译了。
另外如果没有重新编译而直接加载这个类,并在一个 Bag 实例上调用 stream 方法,则会调用 Collection,stream 方法。
1.6 默认方法冲突
一个接口中将一个方法定义为默认方法,然后又在超类或另一个接口中定义了同样的方法
1、扩展接口优先
,如果扩展接口提供了一个具体方法,同名而且有相同参数类型的默认方法会被忽略。
package Interfaces;
public interface Person {
default String speaks(){
return "person";}
}
package Interfaces;
public interface Student extends Person {
default String speaks(){
return "student";}
}
package Interfaces;
public class InterfaceTest implements Student, Person{
public static void main(String[] args) {
InterfaceTest interfaceTest = new InterfaceTest();
System.out.println(interfaceTest.speaks());
// 输出 student
}
}
2、接口冲突
如果一个接 供了一个默认方法. 另一个接口提供了一个同名而且参数
类型相同的方法 (不论是否是默认方法),必须覆盖这个方法来解决冲突。
package Interfaces;
public interface Person {
default String speaks(){
return "person";}
}
package Interfaces;
public interface Student {
default String speaks(){
return "student";}
}
下面的代码就会报错
package Interfaces;
public class InterfaceTest implements Student, Person{
public static void main(String[] args) {
InterfaceTest interfaceTest = new InterfaceTest();
System.out.println(interfaceTest.speaks());
}
}
3、类优先
假设一个类扩展了一个超类,同时实现了一个接口,并且从超类和接口继承了相同的方法。
在这种情况下,只会考虑超类方法,接口的所有和超类相同的默认方法都会被忽略。如果返回类型不同,还会报错。
package Interfaces;
public class InterfaceTest extends Manger implements Person{
public static void main(String[] args) {
InterfaceTest interfaceTest = new InterfaceTest();
System.out.println(interfaceTest.speak());
System.out.println(interfaceTest.call());
// 输出 Manger \n hello
}
}
package Interfaces;
public interface Person {
default String speak(){
return "person";}
default String call(){
return "hello";}
}
package Interfaces;
public