java接口理解

217 阅读4分钟

接口的概述:

  • 接口是描述一个类有什么功能,而并不需要去实现具体功能(给出一些空的方法去描述所提供的功能)

如果类遵从某个特定接口,那么就履行这项服务。(摘自java核心技术卷一)

  • 接口中所有方法都属于public,不需要显示提供
  • 接口没有实例,所以方法不能包含实例,成员变量只能是静态常量(public static修饰,同样不需要显示提供)
  • 接口的声明是用interface,实现接口用implements
  • 接口也可以继承一个超接口,以此来进行拓展
  • 接口不能实例化一个对象,或者说不能new一个对象,但是可以声明一个变量
  • 类只能继承一个超类,但是可以实现多个接口,这样可以得到大部分多继承的好处,同时也避免了大部分多继承带来的麻烦,接口之间用逗号(,)连接
  • jdk 8 中接口可以增加静态方法,public static修饰
  • 接口中还可以提供默认方法,用default修饰,可以同时提供多个默认方法,默认方法不必强制覆盖,可以提高代码的一个重用性

下面从例子中再去深入理解接口的特性:

  1. java中有一个Comparable接口,下面是他的代码:
public interface Comparable<T>{
    int campareTo(Object other);
}

Arrays类中有一个sort方法可以对对象数组进行排序,但是必须满足一个条件,该对象所属的类必须实现了Comparable接口,因为sort方法里面调用了对象的campareTo方法,所以只要实现了Comparable接口,对象就一定包含并且实现了campareTo方法。 再代入到一个雇员管理系统中去实现,下面是他的代码:

package 雇员管理系统;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.Objects;
import java.util.Random;

public class Employee implements Comparable<Employee>{
	private final String name;
	private double salary;
	private final LocalDate hireDay;
	private static int nextId;
	private final int id;
	//静态初始化块,类加载时就会执行
	static{
		Random n = new Random();
		nextId = n.nextInt(10000);
	}
	//初始化块,构造器调用时,根据类中数据域声明的顺序,依次执行
	{
		id = nextId;
		nextId++;
	}
	public Employee(String name,double salary,int year,int month,int day){
		this.name=name;
		this.salary=salary;
		hireDay = LocalDate.of(year,month,day);
	}
	public String getName(){
		return name;
	}
	public double getSalary(){
		return salary;
	}
	public LocalDate getHireDay(){
		return hireDay;
	}
	public void raiseSalary(double raise){
		salary = salary*raise/100+salary;
	}
	public int getId(){
		return id;
	}
	public int compareTo(Employee other){
		//如果第一个参数小于第二个参数返回一个负值,如果相等返回0,否则返回一个正值
		return Double.compare(salary,other.salary);
	}

我在该类中实现了Comparable接口,所有我可以使用Araays.sort()对Employee对象进行排序,下面是测试代码:

package 薪金管理系统;

import java.util.ArrayList;
import java.util.Arrays;

public class EmployeeTest {
	public static void main(String... args){
		//创建一个Employee类型的数组
		Employee[] staff= new Employee[3];
		staff[0] = (new Employee("Gay",75000,1987,12,05));
		staff[1] = (new Employee("Ling",8000,1995,12,12));
		staff[2] = (new Employee("Tao",95000,1996,10,15));
		for(Employee e:staff){
			e.raiseSalary(5);
		}
		//对staff数组进行排序
		Arrays.sort(staff);
		for(Employee e:staff){
			System.out.println("name:"+e.getName()+" salary:"+e.getSalary()+" hireday:"+e.getHireDay()+"id:"+e.getId());
		}
	}
}
注释:如果Employee类没有实现Comparable接口,仅仅只是增加了一个compareTo方法,时候会报错,因为java是个强类型语言,sort方法中包含了类型转换会把staff变量强制转换为Comparable类型。

运行结果:

运行结果
staff数组已经根据salary进行从小到大排序了。

package java接口;

public interface Mouseable {
	default void mouseClick(){
		//可以调用任何方法
		mousePrint();
	}
	default public void mousePressed(){}
	public static void mousePrint(){
		System.out.println("this is a mouse!");
	}
}

package java接口;

public class MouseTest implements Mouseable {
}

默认方法不必强制覆盖,并且可以调用任何方法。
默认方法会遇到冲突问题,遵循俩大原则:

  • 类优先原则,继承的一个超类,和实现的一个接口中,如果包含同名而且参数类型相同的方法,会优先使用超类中的方法
  • 实现的俩个接口中如果包含同名而且参数类型相同的方法,必须覆盖这个方法来解决冲突 举个例子:
package java接口;

public interface Person {
	default String getName(){
		return getClass().getName();
	}

}
package java接口;

public interface Named {
	default String getName(){
		return getClass().getName();
	}
}
package java接口;

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

以上就是俩个接口默认方法冲突的情况,需要覆盖getName来解决二义性,否则就会报错。


java接口在lambda表达式中也有应用,还有很多很多地方,需要了解的可以上网查询。

!!希望各位大佬能多多指教