概念
1.从功能上看,实现接口就扩展了某些功能
2,从规则上看,是接口定义者都需要遵守的某种规则
3,从抽象上看,接口是特殊的抽象类
规则
1.属性必须为公开 静态 常量 (publie static final)
. 由于修饰符固定 ,所以可以省略或者缺失编译器会自动填充
3.方法必须为公开抽象方法(public abstract)
4.没有构造方法
5.不能实例化构造
实现类
[public] class 类名 implements 接口名{}
规则
1.实现类必须对接口中的所有抽象方法提供方法实现
。可以将实现类声明为抽象类避免方法重写,但是不推荐
2。一个实现类可以实现多个实现类,一个接口也可以拥有多个实现类(多实现)
[public] class 类名 implements 接口名1,2 ...{}
3,当实现类实现多个接口时, 必须对所有接口的所有抽象方法提供方法实现
4,一个类可以同时继承父类和实现接口,必须先写继承再写实现
[public] class 类名 extends 父类类名 implements 接口名{
}
5,仍然可以使用多态创建对象(非常推荐)
接口名 引用名=new 实现类名();
6,接口与实现类之间的多态应用规则与父子类相同,一模一样
.只能调用引用类型中的内容
调用独有内容需要类型强转
实现类名 引用名=(实现类名) 接口引用名;
-
-
仍然可以使用instanceof关键字判断类型兼容
引用名 instanceof 接口名|实现类名
-
接口与实现类之间仍然适用多态的三个使用场景
-
/*
* 定义一个接口IC 内置方法method1:计算1-100的和并输出
* method2:传入整型参数,判断返回奇偶性
*
* 为接口IC定义声明实现类,并重写所有方法
* 定义测试类,要求利用多态创建实现类对象,并调用方法测试
* */
package com.by.dao;
public interface IC {
/**
* 计算1-100的和并输出
*/
public void method1();
/**
* 判断返回奇偶性
* @param n 整数值
* @return 是否为偶数
*/
public boolean method2(int n);
}
//实现类
package com.by.dao.impl;
import com.by.dao.IC;
public class ICImpl implements IC {
@Override
public void method1() {
int sum=0;//累加器
for (int i = 0; i <=100; i++) {
sum += i;
}
System.out.println(sum);
}
@Override
public boolean method2(int n) {
return n % 2 == 0 ? true : false;
}
}
//测试类
package com.by.test;
import com.by.dao.IC;
import com.by.dao.impl.ICImpl;
public class TestIC {
public static void main(String[] args) {
//利用多态创建对象
IC ic = new ICImpl();
ic.method1();
System.out.println(ic.method2(10) ? "偶数" : "奇数");
}
}
/* * 案例: * 定义一个工作接口-Work 内置工作方法-work() * 定义两个实现类,分别为老师类和工人类,实现接口 * * 定义测试类,创建Work数组,存放若干个老师和工人对象,并遍历数组调用work方法查看 * 需求2:统计数组中老师的数量 * * */ package com.by.dao; public interface Work { /** * 工作 */ public void work(); } //实现类 package com.by.dao.impl; import com.by.dao.Work; public class Teacher implements Work { @Override public void work() { System.out.println("老师在讲课"); } } public class Worker implements Work { @Override public void work() { System.out.println("工人在工作"); } } //测试类 package com.by.test; import com.by.dao.Work; import com.by.dao.impl.Teacher; import com.by.dao.impl.Worker; public class TestWork { public static void main(String[] args) { //创建一个Work数组 Work ws[] = {new Teacher(), new Teacher(), new Worker(), new Worker()}; //遍历数组 for (int i = 0; i < ws.length; i++) { ws[i].work(); } //统计老师的数量 int sum=0;//累加器 for (int i = 0; i < ws.length; i++) { //判断当前元素能否与老师兼容 if (ws[i] instanceof Teacher) { sum++; } } System.out.println("老师的数量为:" + sum); } }
/* * 在测试类中定义函数,传入参数,要求能够执行出“老师在讲课”或者“工人在工作” * * 在测试类中定义函数,传入Work类型的数组,要求找出所有的老师对象并放入Teacher数组中返回 * */ package com.by.test; import com.by.dao.Work; import com.by.dao.impl.Teacher; import com.by.dao.impl.Worker; public class TestWork { public static void main(String[] args) { method1(new Teacher()); method1(new Worker()); //创建一个Work数组 Work ws[] = {new Teacher(), new Teacher(), new Worker(), new Worker()}; //调用方法测试并接收返回值 Teacher[] ts = method2(ws); System.out.println("ts数组的长度为:"+ts.length); } public static void method1(Work w){//Work w=new Worker() w.work(); } public static Teacher[] method2(Work[] ws){ //统计ws数组中teacher的数量 int sum=0;//累加器 for (int i = 0; i < ws.length; i++) { //判断当前元素能否与老师兼容 if (ws[i] instanceof Teacher) { sum++; } } //用来返回的数组 Teacher[] ts = new Teacher[sum]; //将ws数组中所有的teacher对象放入ts数组 int j=0;//代表ts数组的下标 for (int i = 0; i < ws.length; i++) { //判断当前元素是否与teacher兼容 if (ws[i] instanceof Teacher) { //将当前对象放入ts数组 ts[j] = (Teacher) ws[i]; j++; } } return ts; } }
/* * 在测试类中定义函数,传入整型参数n,要求如果n为偶数返回Teacher对象,否则返回Worker对象 * */ public static void main(String[] args) { //调用method3 Work w1 = method3(10); Work w2 = method3(11); w1.work(); w2.work(); } public static Work method3(int n){ return n % 2 == 0 ? new Teacher() : new Worker(); }
接口间的继承
-
一个接口可以继承多个接口(多继承)
interface 子接口名 extends 父接口名1,父接口名2..{ }
-
子接口可以继承拥有父接口中的所有内容
接口和抽象类的区别
抽象类 | 接口 | |
---|---|---|
关键字 | abstract class | interface |
属性 | 不做具体要求 | 公开静态常量 |
方法 | 可以存在非抽象方法 | 公开抽象方法 |
构造 | 有 | 无 |
继承性 | 单继承 | 多继承 |
接口高级
高版本的接口
JDK8.0
-
公开的默认方法
public default 返回值类型 方法名(参数列表){ //操作语句 }
public为访问修饰符,default为标识符,作用是与抽象方法做区分
-
当父类中的方法体内容与接口中的出现冲突时,优先执行父类(类优先原则)
-
当多个接口中的方法体内容出现冲突时,实现类必须对冲突方法再次提供重写,然后使用自身内容
-
-
公开的静态方法
public static 返回值类型 方法名(参数列表){ //操作语句 }
-
可以通过
接口名.方法名(实参)
的方式直接调用执行
-
JDK9.0
私有方法
private 返回值类型 方法名(参数列表){ //操作语句 }
接口回调
“开闭原则”:扩展开放,修改关闭
允许在现有代码的基础上扩展功能,但是前提时不允许更改已有的代码
概念
将方法的形参声明为接口类型,在传入实参时可以传入不同的实现类对象
本质就是多态的第二个使用场景的体现
/* * 定义一个灯泡接口,要求内置发光方法 * 定义三个实现类,分别表示红灯泡、绿灯泡、蓝灯泡,重写方法 * * 定义测试类 * 定义一个函数,要求传出参数,可以执行“红灯泡发红光”、“绿灯泡发绿光”、“蓝灯泡发蓝光” * * */ package com.by.dao; /** * 灯泡接口 */ public interface Light { /** * 发光方法 */ void shine(); } //实现类 package com.by.dao.impl; import com.by.dao.Light; public class RedLight implements Light { @Override public void shine() { System.out.println("红灯泡发红光"); } } public class GreenLight implements Light { @Override public void shine() { System.out.println("绿灯泡发绿光"); } } public class BlueLight implements Light { @Override public void shine() { System.out.println("蓝灯泡发蓝光"); } } //测试类 package com.by.test; import com.by.dao.Light; import com.by.dao.impl.BlueLight; import com.by.dao.impl.GreenLight; import com.by.dao.impl.RedLight; import com.by.dao.impl.YellewLight; public class TestLight { public static void main(String[] args) { //调用方法时关注实际传入的实现类对象 method(new RedLight()); method(new GreenLight()); method(new BlueLight()); //新增需求:发黄光 1. 创建一个黄灯泡的实现类 2. 调用method方法时传入黄灯泡的对象 method(new YellewLight()); } //只需要关注接口类型的声明 //只需要约束调用者传入要给实现类对象,并且重写发光方法即可 public static void method(Light light) { light.shine(); } }
比较器案例
1.创建比较器接口的实现类吗,并重写排序方法
public class 实现类名 implements Comparator<被排序的类名>{
public int compare(被排序的类名 o1,被排序的类名 o2){
//排序规则
}
}
2,书写排序规则
从小到大
o1的值>o2的值, 返回正数
o1的值<o2的值,返回负数
相当,返回0
从小到大:相反
public class StudentComparator implements Comparator<Student> {@Overridepublic int compare(Student o1, Student o2) {//根据学生年龄从小到大if (o1.getAge() > o2.getAge()) {return 1;} else if (o1.getAge() < o2.getAge()) {return -1;} else {return 0;}}}
3,调用 java.util.Arrays.sort(被排序的数组名,Comparator接口的实现类对象)
执行数组排序
package com.by.test; import com.by.dao.impl.StudentComparator; import com.by.entity.Student; import java.util.Arrays; public class TestComparator { public static void main(String[] args) { /*int[] arr = {10, 2, 99, 77}; //从小到大的排序 Arrays.sort(arr); for (int i = 0; i < arr.length; i++) { System.out.print(arr[i]+" "); }*/ //创建一个学生数组 Student[] ss = {new Student("zhangsan", 20, 98), new Student("lisi", 19, 88), new Student("wangwu", 21, 97)}; //根据学生年龄从小到大对其排序 Arrays.sort(ss,new StudentComparator()); //查看 for (int i = 0; i < ss.length; i++) { System.out.println(ss[i].getName()+" "+ss[i].getAge()+" "+ss[i].getScore()); } } /* * * interface 排序接口{ * //书写排序规则 * 排序方法(); * } * * class 实现类 implements 排序接口{ * 排序方法(){ * 书写排序规则 * } * } * * public static void sort(被排序的数组名,包含排序规则的接口){ * * } * *调用 sort(数组名,排序接口的实现类对象) * * */ }
接口的好处
1.代码解耦合
2.提升代码扩展性
3.优化代码结构