使用的教材是java核心技术卷1,我将跟着这本书的章节同时配合视频资源来进行学习基础java知识。
day038 接口(接口概念、接口的特性)
1.接口概念
在Java程序设计语言中,接口不是类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义。
我们经常听到服务提供商这样说:“如果类遵从某个特定接口,那么就履行这项服务“。下面给出一个具体的示例。Arrays类中的sort方法承诺可以对对象数组进行排序,但要求满足下列前提:对象所属的类必须实现了Comparable接口。
下面是Comparable接口的代码:
public interface Comparable
{
int compareTo(Object other);
}
这就是说,任何实现Comparable接口的类都需要包含compareTo方法,并且这个方法的参数必须是一个Object对象,返回一个整型数值。
在JavaSE 5.0中,Comparable接口已经改进为泛型类型。
public interface Comparable<T>
{
int compareTo(T other);//parameter has type T
}
例如,在实现Comparable接口的类中,必须提供下列方法
int coirpareTo(Employee other)
还可以使用不带类型参数的“原始”Comparable类型。这样一来,compareTo方法就有一个Object类型的参数,必须手动将compareTo方法的这个参数强制转换为所希望的类型。
接口中的所有方法自动地属于public。因此,在接口中声明方法时,不必提供关键字public。
当然,接口中还有一个没有明确说明的附加要求:在调用X.c0mpareT0(y)的时候,这个compareTo方法必须确实比较两个对象的内容,并返回比较的结果。当x小于y时,返回一个负数;当x等于y时,返回0;否则返回一个正数。
上面这个接口只有一个方法,而有些接口可能包含多个方法。稍后可以看到,在接口中还可以定义常4L然而,更为重要的是要知道接口不能提供哪些功能。接口绝不能含有实例域。
提供实例域和方法实现的任务应该由实现接口的那个类来完成。因此,可以将接口看成是没有实例域的抽象类。但是这两个概念还是有一定区别的现在。
假设希望使用Arrays类的sort方法对Employee对象数组进行排序,Employee类就必须实现Comparable接口。
为了让类实现一个接口,通常需要下面两个步骤:
1)将类声明为实现给定的接口。
2)对接口中的所有方法进行定义。
要将类声明为实现某个接口,需要使用关键字implements:
class Employee implements Comparable
当然,这里的Employee类需要提供compareTo方法。假设希望根据雇员的薪水进行比较。以下是compareTo方法的实现:
public int compareTo(Object otherObject)
{
Employee other=(Employee)otherObject;
return Double.compare(salary,other.salary);
}
在这里,我们使用了静态Double.compare方法,如果第一个参数小于第二个参数,它会返回一个负值;如果二者相等则返回0;否则返回一个正值。
在接口声明中,没有将compareTo方法声明为public,这是因为在接口中的所有方法都自动地是public。不过,在实现接口时,必须把方法声明为public;否则,编译器将认为这个方法的访问属性是包可见性,即类的默认访问属性,之后编译器就会给出试图提供更严格的访问权限的警告信息。
现在,我们已经看到,要让一个类使用排序服务必须让它实现compareTo方法。这是理所当然的,因为要向sort方法提供对象的比较方式。但是为什么不能在Employee类直接提供一个compareTo方法,而必须实现Comparable接口呢?
主要原因在于Java程序设计语言是一种强类型(strongly typed)语言。在调用方法的时候,编译器将会检查这个方法是否存在。在sort方法中可能存在下面这样的语句:
if(a[i].compareTo(a[j])>0)
{
//rearrange a[i] and a[j]
...
}
为此,编译器必须确认a[i]—定有compareTo方法。如果a是一个Comparable对象的数组,就可以确保拥有compareTo方法,因为每个实现Comparable接口的类都必须提供这个方法的定义。
下面的程序1给出了对一个Employee类(程序2)实例数组进行排序的完整代码,用于对一个员工数组排序。
程序1:
/**
*@author zzehao
*/
import java.util.*;
public class EmployeeSortTest
{
public static void main(String[] agrs)
{
Employee[] staff = new Employee[3];
staff[0] = new Employee("Harry Hacker",35000);
staff[1] = new Employee("Carl Cracker",75000);
staff[2] = new Employee("Tony Tester",38000);
Arrays.sort(staff);
//print out information about all Employee objects
for (Employee e : staff)
{
System.out.println("name="+e.getName()+",salary="+e.getSalary());
}
}
}
程序2:
/**
*@author zzehao
*/
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;
}
public int compareTo(Employee other)
{
return Double.compare(salary,other.salary);
}
}
运行的结果:
2.接口的特性
接口不是类,尤其不能使用new运算符实例化一个接口:
x = new Comparable(...);//ERROR
然而,尽管不能构造接口的对象,却能声明接口的变量:
Comparable x;//OK
接口变量必须弓I用实现了接口的类对象:
x = new Employee(...);//OK provided Employee implements Comparable
接下来,如同使用instanceof检查一个对象是否属于某个特定类一样,也可以使用instance检查一个对象是否实现了某个特定的接口:
if(anObject instanceofComparable){...}
与可以建立类的继承关系一样,接口也可以被扩展。这里允许存在多条从具有较高通用性的接口到较高专用性的接口的链。例如,假设有一个称为Moveable的接口:
public interface Moveable
{
void move(double x,double y);
}
然后,可以以它为基础扩展一个叫做Powered的接口:
public interface Powered extends Moveable
{
double milesPerCallon();
}
虽然在接口中不能包含实例域或静态方法,但却可以包含常量。例如:
public interface Powered extends Moveable
{
double milesPerCallon();
double SPEED.LIHIT=95;
//a public static final constant
}
与接口中的方法都自动地被设置为public—样,接口中的域将被自动设为public static final。
有些接口只定义了常量,而没有定义方法。例如,在标准库中有一个SwingConstants就是这样一个接口,其中只包含NORTH、SOUTH和HORIZONTAL等常量。任何实现SwingConstants接口的类都自动地继承了这些常量,并可以在方法中直接地引用NORTH,而不必采用SwingConstants.NORTH这样的繁琐书写形式。然而,这样应用接口似乎有点偏离了接口概念的初衷,最好不要这样使用它。
尽管每个类只能够拥有一个超类,但却可以实现多个接口。这就为定义类的行为提供了极大的灵活性。例如,Java程序设计语言有一个非常重要的内置接口,称为Cloneable。如果某个类实现了这个Cloneable接口,Object类中的clone方法就可以创建类对象的一个拷贝。如果希望自己设计的类拥有克隆和比较的能力,只要实现这两个接口就可以了。使用逗号将实现的各个接口分隔开。
class Employee implements Cloneable,Comparable