6.1 接口
接口(interface)技术主要描述类具有什么功能,而并不给出每个功能的具体实现。一个类可以实现(implement)一个或多个接口,并在需要借口的地方,随时使用实现了相应接口的对象。
对象的克隆是指创建一个新对象,且新对象的状态与原始对象的状态相同,当对克隆的新对象进行修改的时候,不会影响原始对象的状态。
内部类(inner class)定义在另一个类的内部,其中的方法可以访问它们的外部类的域,这是一项复杂的技术。内部类技术主要用于设计具有相互协作关系的类集合。特别是在编写处理GUI事件的代码时,使用它可以让代码看起来简练专业。
代理(proxy)是一种实现任意接口的对象。代理是一种非常专业的构造工具,可以用来构建系统级的工具。
6.1 接口
在java中,接口不是类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义。
“如果类遵从某个特定的接口,那么就履行这项服务”
Arrays类中的sort方法承诺可以对对象数组进行排序,但要求满足下列前提:对象所属的类必须实现Comparable接口。以下是Comparable接口的代码:
public interface Comparable { int compareTo(Object other); }
也就是说,任何实现了Comparable接口的类都需要包含compareTo方法,并且这个方法的参数必须是一个Object对象,返回一个整形数值。
接口中所有的方法都自动的属于public,因此,在接口声明方法中,不必提供关键字public。
接口中还有一个没有明确说明的附件说明:在调用x.compareTo(y)的时候,这个compareTo方法必须确实比较两个对象的内容,并返回比较结果。
当x < y的时候,返回一个负数;
当x = y的时候,返回0;
当x > y的时候,返回一个正数。
上述接口只有一个方法,而有些接口可能包含多个方法,在接口中还可以定义常量,然而,更重要的是要知道接口不能提供哪些功能,接口绝不能含有实例域,也不能在接口中实现方法。提供实例域和方法实现的任务应该由实现接口的那个类来实现。因此,接口可以看成是没有实例域的抽象类。但这两者又是有区别的。
假设希望使用Arrays类的sort方法对Employee对象组进行排序,Employee类就必须实现Comparable接口。
为了让类实现一个借口,通常需要如下两个步骤:
(1)让类声明为实现给定的接口;
(2)对接口中的所有方法进行定义。
要将类声明为实现某个接口,需要使用关键字implements:class implements Caparable
这里的Employee类需要提供compareTo方法。假设对薪水进行比较:
public int compareTo(Object otherObject) { Employee other = (Employee) otherObject; return Double.compare(salary, other.salary); }
在这里,我们使用了静态的Double.compare方法。
在接口声明的时候,没有将compareTo方法声明为public,因为在接口中的所有方法都自动的是public,不过在实现接口的时候,必须将方法声明为public,否则编译器将认为这个方法的访问属性是包可见性,即类的默认访问属性。
要让类使用排序服务必须实现compareTo方法,因为要向sort方法提供对象的比较方式,因为java是一种强类型的语言,在调用方法的时候,编译器会检查这个方法是否存在。在sort方法中可能存在比较语句,为此,编译器必须确认a[i]一定有compareTo方法,如果a是一个Comparable对象的数组,就可以确保拥有compareTo方法,因为每个实现Comparable接口的类必须提供这个方法的定义。
Employee.java
package implements_6_1; public class Employee implements Comparable<Employee> { private String name; private double salary; public Employee(String n, double s) { name = n; salary = s; } 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); } }
EmployeeSortTest.java
package implements_6_1; import java.util.Arrays; public class EmployeeSortTest { public static void main(String args[]) { Employee[] staff = new Employee[3]; staff[0] = new Employee("Harry hacker", 35000); staff[1] = new Employee("Carl Craker", 75000); staff[2] = new Employee("Tony Tester", 38000); Arrays.sort(staff); for(Employee e:staff) { System.out.println("name = " + e.getName() + ",salary = " + e.getSalary()); } }
首先给出了Employee的对象,然后按照salary进行排序。
6.1.1 接口的特性
接口不是类,不能使用new运算符实例化接口,尽管不能构造接口的对象,但却能声明接口的变量。
与可以建立类的继承关系一样,接口可以被扩展,这里允许存在多条从具有较高通用性的接口到较高专用性的接口的链。
假设有一个Moveable的接口:
public interface Moveable { void move(double x, double y); }
然后,可以将以它为基础扩展一个叫做Powerd的接口:
public interface Powerd extends Moveable { double milesPerGallon(); }
虽然在接口中不能包含实例域或静态方法,但却不可以包含常量。例如:
public interface Powerd extends Moveable { double milesPerGallon(); double SPEED_LIMIT = 95;//a public static final constant }
与接口中的方法都自动被设置为public一样,接口中的域将被自动设置为public static final。
尽管每个类只能够拥有一个超类,但却可以实现多个借口。这就为定义类的行为提供了极大的灵活性。例如,java程序设计语言有一个非常重要的内置接口,称为Cloneable。如果某各类实现了这个Cloneable接口,Object类中的clone方法就可以创建类对象的一个拷贝。如果希望自己设计的类拥有克隆和比较的能力,只需要实现这两个接口即可。
class Employee implements Cloneable, Comparable
6.1.2 接口与抽象类
使用抽象类表示通用属性存在问题:每个类只能扩展一个类。假设Employee类已经扩展了一个类,例如Person,那么就不能一次扩展两个类。
但每个类可以实现多个接口
class Employee implements Cloneable, Comparable
class Employee extends Person implements Comparable
C++可以多继承,但是java不支持多继承,主要原因是多继承会使得语言本身变得非常复杂,效率会降低。