接口
认识接口
- Java提供了一个关键字 interface,用这个关键字我们可以定义出一个特殊的结构:接口。
public interface 接口名{ //成员变量(常量) //成员方法(抽象方法) }
在接口中,不需要将变量用final修饰成常量,它会自动转为常量,例如:
public interface A{ double R = 3.14; //相当于 public static final double r = 3.14; }
注意:常量建议使用大写来命名。
方法也同样,接口会自动将方法转为抽象方法,例如:
public interface A{ void run(); //相当于public abstract void run(); }
故而接口中的方法只能有签名,不能有方法体。
注意:接口不能创建对象;接口是用来被类实现(implements)的,实现接口的类称为实现类。
修饰符 class 实现类 implements 接口1,接口2,接口3,...{
}
- 一个类可以实现多个接口(接口可以理解成干爹),实现类实现多个接口,必须重写完全部接口的全部抽象方法,否则实现类需要定义成抽象类。
接口的好处
- 弥补了类单继承的不足,一个类同时可以实现多个接口。
- 让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现。
例如下面这种情况,一个类继承了几个类之后就不能再继承其他类了,这时需要其他功能就可以用接口来实现了。
public class Test{ public static void main(String[] args){ Student s = new A(); } } class Student{ } class A extends Student{ }
接口为其拓展更多功能:
public class Test{ public static void main(String[] args){ Singer s = new A(); //或是 Driver s = new A(); } } class A extends Student implements Driver,Singer{ @override public void drive{ } @override public void sing{ } } class Student{ } interface Driver{ void drive(); } interface Singer{ void sing(); }
1.使用接口有啥好处,第一个好处是什么?
- 可以解决类单继承的问题,通过接口,我们可以让一个类有一个亲爹的同时,还可以找多个干爹去扩展自己的功能。
2.为什么我们要通过接口,也就是去找干爹,来扩展自己的功能呢?
- 因为通过接口去找干爹,别人通过implements的接口,就可以显性地知道你是谁,从而也就可以放心地把你当作谁来用了。
3.使用接口的第二个好处是什么?
- 一个类我们说可以实现多个接口,同样,一个接口也可以被多个类实现。这样做的好处是我们的程序就可以面相接口编程了,这样我们程序员就可以很方便的灵活切换各种业务实现了。
接口的综合案例
需求
请设计一个班级学生的信息管理模块:学生的数据有:姓名、性别、成绩
功能1:要求打印出全班学生的信息;
功能2:要求打印出全班学生的平均成绩。
注意!以上功能的业务实现是有多套方案的,比如:
- 第1套方案:能打印出班级全部学生的信息;能打印班级全部学生的平均分。
- 第2套方案:能打印出班级全部学生的信息(包含男女人数);能打印班级全部学生的平均分(要求是去掉最高分、最低分)
要求:系统可以支持灵活的切换这些实现方案。
先定义出基本的学生类:
学生类
package user.interfaceDemo; public class Student { private String name; private char sex; private double score; public Student() { } public Student(String name, char sex, double score) { this.name = name; this.sex = sex; this.score = score; } public String getName() { return name; } public void setName(String name) { this.name = name; } public char getSex() { return sex; } public void setSex(char sex) { this.sex = sex; } public double getScore() { return score; } public void setScore(double score) { this.score = score; } }
因为我们要设计班级学生的信息管理模块,所以接下来把班级管理类定义出来,其中有包含学生的班级集合以及班级里面的学生信息。
班级管理类
package user.interfaceDemo; import java.util.ArrayList; public class ClassManager { private ArrayList<Student> students = new ArrayList<>(); //构造器初始化出班级内部的信息 public ClassManager(){ students.add(new Student("余周周",'女',99)); students.add(new Student("林杨",'男',100)); students.add(new Student("蒋川",'男',80)); students.add(new Student("凌翔茜",'女',90)); } //打印出全班学生的信息 public void printInfo(){ } //打印出全班学生的平均成绩 public void printScore(){ } }
实现的方法这部分因为要能够灵活切换,所以需要用接口实现,先空着,去定义接口。
学生操作接口
package user.interfaceDemo; import java.util.ArrayList; public interface StudentOperator { void printAllInfo(ArrayList<Student> students); void printAverageScore(ArrayList<Student> students); }
下面就定义两个学生操作类,在学生操作类中去实现学生操作接口,分别重写接口的两个方法。
学生操作类
第一套方案:
package user.interfaceDemo; import java.util.ArrayList; public class StudentOperatorImp1 implements StudentOperator{ @Override public void printAllInfo(ArrayList<Student> students) { System.out.println("=======全班所有学生信息如下======="); for (int i = 0; i < students.size(); i++) { Student s = students.get(i); System.out.println("姓名:" + s.getName()); System.out.println("性别:" + s.getSex()); System.out.println("分数:" + s.getScore()); if(i != students.size() - 1){ System.out.println("--------------------"); } } System.out.println("========================"); } @Override public void printAverageScore(ArrayList<Student> students) { double allScore = 0.0; for (int i = 0; i < students.size(); i++) { Student s = students.get(i); allScore += s.getScore(); } System.out.println("该班级的平均分为:" + ( allScore / students.size() )); } }
第二套方案:
package user.interfaceDemo; import java.util.ArrayList; public class StudentOperatorImp2 implements StudentOperator{ @Override public void printAllInfo(ArrayList<Student> students) { System.out.println("=======全班所有学生信息如下======="); int count1 = 0; //用于记录男生的数量 int count2 = 0; //用于记录女生的数量 for (int i = 0; i < students.size(); i++) { Student s = students.get(i); System.out.println("姓名:" + s.getName()); System.out.println("性别:" + s.getSex()); System.out.println("分数:" + s.getScore()); if(i != students.size() - 1){ System.out.println("--------------------"); } if(s.getSex() == '男'){ count1++; }else{ count2++; } } System.out.println("男生人数为:" + count1 + "人"); System.out.println("女生人数为:" + count2 + "人"); System.out.println("班级总人数为:" + students.size() + "人"); System.out.println("========================"); } @Override public void printAverageScore(ArrayList<Student> students) { double allScore = 0.0; double max = students.get(0).getScore(); double min = students.get(0).getScore(); for (int i = 0; i < students.size(); i++) { Student s = students.get(i); if(s.getScore() > max) max = s.getScore(); if(s.getScore() < min) min = s.getScore(); allScore += s.getScore(); } System.out.println("该班级的最高分是:" + max + "分"); System.out.println("该班级的最低分是:" + min + "分"); System.out.println("该班级的平均分为:" + ( (allScore - max - min) / (students.size() - 2) )); } }
接下来回到班级管理类,完善功能:
完善班级管理类
package user.interfaceDemo; import java.util.ArrayList; public class ClassManager { private ArrayList<Student> students = new ArrayList<>(); //创建出学生操作对象,给下面的方法进行调用,其中StudentOperatorImp1可以替换为StudentOperatorImp2,功能就进行了变化. private StudentOperator studentOperator = new StudentOperatorImp1(); //构造器初始化出班级内部的信息 public ClassManager(){ students.add(new Student("余周周",'女',99)); students.add(new Student("林杨",'男',100)); students.add(new Student("蒋川",'男',80)); students.add(new Student("凌翔茜",'女',90)); } //打印出全班学生的信息 public void printInfo(){ studentOperator.printAllInfo(students); } //打印出全班学生的平均成绩 public void printScore(){ studentOperator.printAverageScore(students); } }
测试
package user.interfaceDemo; public class Test { public static void main(String[] args) { ClassManager cc = new ClassManager(); cc.printInfo(); cc.printScore(); } }
第一套方案的运行结果:
改为第二套方案:
第二套方案的运行结果为:
END