一,接口注意点
-
接口不是类,而是对类一组需求描述,这些类要遵从接口描述的统一格式进行定义
-
接口(interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
-
接口包含类要实现的方法,类描述对象的属性和方法。
-
除非实现接口的类是抽象类,否则该类要定义接口中所有的方法
-
如果一个类既要继承另一个类又要实现一个接口,只能先继承再实现
class son extend father implements interface{ // }
二,接口与类的区别
-
接口不能实例化对象,但是可以被实现。。
-
接口没有构造方法。
-
接口内所有方法必须是抽象方法。
-
接口不是被类继承,是被类实现。
-
接口支持多继承,类不能。
三,接口与类的相似点
-
一个接口有多个方法。
-
接口文件保存在.java结尾的文件夹中,文件使用接口名,字节码保存在.class结尾文件中。
-
接口相应的文件需保存在与包名相匹配的结构目录中
四,接口特性
-
不能使用new运算符实例化一个接口
//错误的 x = new Comparable(.....); //Comparable是一个接口
-
接口内能声明变量
Comparable a; //接口变量必须引用实现了接口的类对象,或者就是一个空指针 a = new Employee(.....);
-
可以使用instanceof检查一个对象是否属于某个特定类
//测试左边的对象是否是右边类的实例 if(anObject instanceof Comparable)
-
接口可扩展
public interface Moveable { void move(double x,double y); } //扩展一个叫做Powered的接口 public interface Powered extends Moveable { double milesPerGallon(); }
-
接口不能包含实例域或静态方法,但是可以包含常量(java8可以加静态方法了,但是这有违将接口作为抽象规范的初衷)
//接口中的方法自动的被设置为public abstract //接口中的变量都自动设为public static final public interface Powered extends Moveable { double milesPerGallon(); //等价于 public abstract double milesPerGallon(); double num = 16.6; //等价于 public static final double num = 16.6;
}
五:简单案例
public interface Person{ //接口 void father(); void mother(); }
public class Family implements Person{ //实现类 public void father(){ System.out.println("我是爸爸"); } public void mother(){ System.out.println("我是妈妈"); } }
六:默认方法
-
为借口方法提供一个默认实现,用default修饰符修饰
public interface Comparable<T>{ default int compareTo(T other){ return 0; } }
-
默认方法的作用
一旦接口需要发生变化,实现这些接口的类也就需要更新,但是如果是很多类,那这样操作起来就很麻烦。比如Collection接口为例,在Java SE8中,为了这个接口添加了一个默认方法stream方法,假设stream方法不是一个默认方法,那Bag类将不能编译(Bag类并没有实现这个方法),为接口增加一个非默认方法不能保证“源代码兼容”,假设不重新编译这个类,而是使用原先的一个包含这个类的JAR文件,这个类仍能正常加载和构造Bag实例(尽管没有stream方法),但是在Bag实例上调用这个方法是,就会出现AbstractMethodError。如果将stream设为默认方法将会解决上面俩个问题。
-
解决默认方法冲突
如果先在一个接口中将一个方法设为默认方法,又在一个超类或者另一个接口定义了同样的方法,会是什么情况?
- 超类优先。如果超类提供了一个具体方法,同名而且有相同参数类型的默认方法会被忽略。
- 接口冲突,俩个接口提供了同名且参数类型(不论是否是默认参数)相同的方法,必须覆盖这个方法来解决
interface School{ defualt String getName(){ return getClass().getName()+" "+hasCode(); } } class Student implements School,Family{ //School和Family接口都有getName默认方法 public String getName(){ return School.super.getName(); } }
七:问题与扩展
-
为什么还要用接口,不是已经有抽象类了吗?
//比如 abstract class Comparable{ public abstract int compareTo(Object other); } //然后 Employee类再扩展这个抽象类,并实现方法 class Employee extends Comparable{ public int compareTo{ ....... } } //为什么不这样?
因为抽象类表示通用属性存在这样一个问题:每个类只能扩展一个类,假如Employee类已经扩展一个类Person了,就不能扩展其他类了
class Employee extends Person,Comparable //错误 class Employee extends Person implements Comparable //正确
-
Comparable接口
public interface Comparable{ int compareTo(Object other) } //在java SE5.0中,Comparable接口已改进为泛型类型 public inteface Comparable<T>{ int compareTo(T other) //int compareTo(Employee other) } //以下是实现方法 public int compareTo(Object otherObject){ Employee other = (Employee) otherObject; //调用静态方法Double.compareTo 比较salary与other salary返回-1 0 1 return Double.compare(salary,other.salary); } //最好用这个,泛型 class Employee implements Comparable<Employee>{ public int compareTo(Employee other){ return Double.compare(salary,other.salary); } }
-
为什么不能再Employee类中直接提供compareTo方法,而要去实现Comparable接口?
java是强类型语言,在调用方法时将会检查这个方法是否存在。sort方法可能存下面的语句:
//Employee [] a = new .... 调用
if(a[i].compareTo(a[j])>0){ ............ }
为此,编译器需确认a[i]一定有compareTo方法,因为每个实现Comparable接口的类都必须提供这个方法的定义,换一种角度,如果将Array类中的sort方法定义为接受一个Comparable[]数组就可以在使用元素类型没有实现Comparable接口的数组作为参数调用sort方法。在这种情况下sort可以接受一个object[]数组,并对其进行笨拙的转换,如果a[i]不属于实现了Comparable的类。虚拟机将会抛出异常
//案例 public class EmployeeSortTest { public static void main(String[] args) { Employee[] staff = new Employee[3]; staff[0] = new Employee("hjj",20000); ... //注意Employee类里是没有sort方法的,确认staff[i]是否有compareTo方法,有,并且a[i]属于实现了Comparable的类
//Arrays类继承了Comparable接口 Arrays.sort(staff); } }
public class Employee implements Comparable<Employee>{ private String name; private double salary; ..... ..... //实现compareTo方法 public int compare(Employee other) { return Double.compare(salary,other.salary); } }