我是靠谱客的博主 落寞凉面,最近开发中收集的这篇文章主要介绍18.接口【Java温故系列】,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

参考自–《Java核心技术卷1》

接口(interface)

      • 1 接口简述
    • 在这里插入图片描述
      • 2 接口的特性
      • 3 接口与抽象类
      • 4 静态方法
      • 5 默认方法
      • 6 解决默认方法冲突

接口技术主要用来描述具有什么功能,而并不给出每个功能的具体实现。一个类可以实现( implements)一个或多个接口,并在需要接口的地方,随时使用实现了相应接口的对象。


1 接口简述

接口概念:接口不是类,而是对类的一组需求描述,这些类要遵从接口描述的统一格式进行定义。

接口中的所有方法自动地属于 public,因此,在接口中声明方法时,不必提供关键字 public。

接口中可以定义常量。但,接口绝不能含义实例域,在 Java SE 8之前,也不能在接口中实现方法,现在已经可以在接口中提供简单方法了(当然,这些方法不能引用实例域—接口中没有实例)。

提供实例域和方法实现的任务应该由实现接口的那个类来完成。

现在,假设使用 Arrays 类的 sort 方法对 Employee 对象数组进行排序,Employee 类就必须实现接口 Comparable 接口:

为了让类实现一个接口,通常需要两个步骤:

1)将类声明为实现给定的接口

2)对接口中的所有方法进行定义

Comparable 接口:

public interface Comparable<T>{
	int compareTo(T o);  //参数类型为T
}

Employee 类:需要使用关键字 implements

public class Employee implements Comparable {
	private String name;
    private double salary;
    ...
    @Override
    public int compareTo(Object o) {
        //比较 salary
        Employee other = (Employee)o;
        return Double.compare(salary,other.salary);
    }
}

这里使用了静态的 Double.compare方法。如果第一个参数小于第二个参数,返回一个负值,;如果二者相等,返回0;否则返回一个正值。

:在接口声明中,没有将 compareTo 方法声明为 public,这是因为接口中的所有方法都自动是 public 的。不过在实现接口时,必须把方法声明为 public。

对于上述 compareTo 方法的实现,还有更好的设计。可以为泛型 Comparable 接口提供一个类型参数:

public class Employee implements Comparable<Employee> {
	private String name;
    private double salary;
    ...
    @Override
    public int compareTo(Employee o) {
        //比较 salary
        return Double.compare(salary,o.salary);
    }
}

:Comparable 接口中的 compareTo 方法将返回一个整型数值。如果两个对象不相等,则返回一个正值或者一个负值。在对两个整数域进行比较,这点非常有用。例如,假设每个雇员都有一个唯一正数 id,并希望根据 id 对雇员进行重新排序,那么就可以返回 id-other.id 。如果第一个 id 小于另一个 id,则返回一个负值,如果两个 id 相等,则返回0,否则返回一个正值。但需要注意整数的范围不能过大,以避免造成减法运算的溢出。若可能溢出,则调用静态 Integer.compare 方法。当然,整型数值的运算不适用于浮点值,浮点值运算:x<y时,Double.compare(x,y) 返回 -1;如果 x>y,则返回 1.

要使一个类使用排序服务必须让它实现 compareTo 方法,此方法向 sort 方法提供对象的比较方式。

在这里插入图片描述

2 接口的特性

接口不是类,尤其不能使用 new 运算符实例化一个接口;然而,尽管不能构造接口对象,却能声明接口的变量;而且,接口变量必须引用实现了接口的类对象:

Comparable x = new Comparable(...);   //错误
Comparable x;   //ok
x = new Employee(...);  //ok , Employee是实现了Comparable的类

如同使用 instanceof 检查一个对象是否属于某个特定类一样,也可以使用 instanceof 检查一个对象所属类是否实现了某个特定的接口:

if(obj instanceof Comparable) {
    //obj是否实现了Comparable接口,实现了返回true,否则返回false
   	...
}

与可以建立类的继承关系一样,接口也可以被扩展,且允许存在多条从具有较高通用性的接口到较高专用性的接口的链,例如:

public interface Moveable{
	void move(double x,double y);
}

然后,可以以它为基础扩展一个叫 Powered 的接口:

public interface Powered extends Moveable{
	double milesPerGallon();
	double SPEED_LIMIT =  95;    //权限为 public static final
}

接口中虽然不能包含实例域或静态方法,但是可用包含常量,与接口中的方法都自动被设置为 public 一样,接口中的域将被自动设为 public static final.

尽管每个类只能够拥有一个超类,但却可以实现多个接口,例如:

public Employee implements Cloneable,Comparable{
	...
}

Employee 类同时继承了 Cloneable,Comparable两个接口,拥有克隆和比较的能力。


3 接口与抽象类

抽象类也可以实现类似接口的功能:

public abstract class Comparable{
	public abstract int compareTo(object obj);
}

再由 Employee 类扩展这个抽象类,并提供 compareTo的方法实现:

public class extends Comparable{
	...
	public int compareTo(Object obj){
		...
	}
	...
}

但,使用抽象类表示通用属性,方法存在这样一个问题:每个类只能扩展一个类。如果 Employee 此前已经扩展了一个类,它就不能扩展第二个类了。但它还能实现其他接口。

:有些语言(如C++)允许一个类有多个超类,此特性称为多重继承。但 Java 并不支持多重继承,其主要原因是多继承会让语言本身变得非常复杂,效率也会降低。

实际上,接口可以提供多重继承的大多数好处,同时还能避免多重继承的复杂性和低效性。


4 静态方法

Java SE 8中,允许在接口中增加静态方法。理论上,没有任何理由认为这是不合法的。只是这样有违将接口作为抽象规范的初衷。

目前为止,通常的做法都是将静态方法放在伴随类中。在标准库中,可以看到成对出现的接口和实用工具类,如 Collection/Collections 或 Path/Paths。

Paths 类是 Path 接口的伴随类,在 Path 接口可以增加以下方法:

public interface Path{
	public static Path get(String first,String... more){
		return FileSystems.getDefault().getPath(first,more);
	}
	...
}

get 方法是 Paths 伴随类实现的方法,若如上给 Path 接口增加了 get 方法,那么,Paths 类就不再是必要的。

在实现自己的类时,不再需要为实用工具方法另外提供一个伴随类,而是直接在接口中增加 静态方法。


5 默认方法

可以为接口方法提供一个默认实现。必须使用 default 修饰符标记这样一个方法。

public interface Comparable<T>{
	default int compareTo(T other){
		return 0;
	}
}

当然,这样并没有多大用处,因为 Comparable 的每一个实际实现都要覆盖 compareTo 方法。不过,有些情况下,默认方法可能很有用:在接口的实现类中不用必须实现接口的默认方法,程序员可以选择自己关心的方法并覆盖实现它。

默认方法可以调用任何其他方法。例如:Collection 接口定义一个便利方法

public interface Collection{
	int size();
	default boolean isEmpty(){
		return size()==0;
	}
	...
}

:在 Java API 中,可以看到很多接口都有相应的伴随类,这些伴随类实现了相应接口的部分或所有方法。在 Java SE 8中,这个技术已经过时。现在可以直接在接口中实现方法。

默认方法的一个重要用法是“接口演化”。以 Collection 接口为例,假设很久以前编写了这样一个类:

public class Bag implements Collection

后来随着 JDK 的更新,又为 Collection 接口增加了 stream 方法。

假设 stream 方法不是一个默认方法,那么 Bag 类将不能编译,因为它没有实现这个新增加的方法。为接口增加一个非默认方法不能保证“源代码兼容”。

不过,假设不重新编译这个类(Bag),而是使用原先的一个包含这个类的 JAR 文件。尽管没有实现这个新方法,这个类仍能正常加载。程序仍能正常构造 Bag 实例,但如果在一个 Bag 实例上调用 stream ,就会出现一个 AbstractMethodError.

将方法实现为一个默认方法就可以解决这2个问题。Bag 类能正常编译,且若没有重新编译而直接加载这个类,并在 Bag 实例上调用 stream 方法,将调用 Collection.stream 方法。


6 解决默认方法冲突

如果先在一个接口中将一个方法定义为默认方法,然后在超类或另一个接口中定义了同样的方法,会发生什么情况?对于这种二义性的问题,Java 有相应的解决规则:

1.超类优先。如果超类提供了一个具体方法,接口中存在的同名且有相同参数类型的默认方法会被忽略。

2.接口冲突。如果一个超接口提供了一个默认方法,另一个接口提供了一个同名且参数类型(不论是否是默认参数)相同,必须覆盖这个方法来解决冲突。

下面看看这两种情况是如何处理的:

:假设存在 Person 超类:

public class Person{
	private name;
	...
	//具体方法
	public String getName(){
		return name;
	}
}

另外一个包含 getName 方法的接口:

interface Named{
    //默认方法
	default String getName(){
		return ...;   
	}
}

有一个继承了 Person 且实现了 Named 接口的类 Student:

public class extends Person implements Named{ 
	... 
}

在这种情况下,只会考虑超类方法,接口的所有默认方法都会被忽略。即 Student 从 Person 继承了 getName 方法,Named 接口是否为 getName 提供了默认实现并不会带来什么区别。这正是“类优先”规则。

“类优先”规则可以确保与之前的 JDK 版本保持兼容性。如果为一个接口增加默认方法,这对于有这个默认方法之前能够正常工作的代码不会有任何影响。

:假设 Person 是一个接口:

public interface Person{
	...
	//默认方法
	default String getName(){
		return ...;
	}
}

若存在一个 Student 类同时实现了 Person 接口和 Named 接口,需要程序员去选择两个冲突方法中的一个,如下所示:

public Student implements Person,Named{
	public String getName(){
        return Person.super.getName();
    }
}

或者,在实现接口的类中覆盖冲突方法。

@Override
public String getName() {
	return null;
}

在 Java 中,两个接口方法的冲突并不重要。如果至少有一个接口提供了默认实现,编译器就会报告错误,而程序员就必须解决这个二义性;但若两个接口都没有为同名且参数类型相同的类型提供默认参数,则不存在冲突,这时,实现类有两个选择:实现这个方法,或者不实现。

public Student implements Person,Named{
	public String getName(){
        return Person.super.getName();
    }
}

或者,在实现接口的类中覆盖冲突方法。

@Override
public String getName() {
	return null;
}

在 Java 中,两个接口方法的冲突并不重要。如果至少有一个接口提供了默认实现,编译器就会报告错误,而程序员就必须解决这个二义性;但若两个接口都没有为同名且参数类型相同的类型提供默认参数,则不存在冲突,这时,实现类有两个选择:实现这个方法,或者不实现。


最后

以上就是落寞凉面为你收集整理的18.接口【Java温故系列】的全部内容,希望文章能够帮你解决18.接口【Java温故系列】所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部