一、终极结论
接口: 1、接口也是一种“引用数据类型” 2、接口是完全抽象的(抽象类是半抽象) 3、接口怎么定义,语法是什么? [修饰符列表] interface 接口名{} 4、接口中只有常量、抽象方法 5、接口当中所有的元素都是public修饰的 6、接口中抽象方法的public abstract可以省略 7、接口中常量public static final可以省略 9、接口中方法不能有方法体 10、接口支持多继承 11、一个"非抽象"的类,实现(可以理解为继承)接口时,必须将接口中所有的"抽象"方法加以实现(重写) 12、一个类可以实现多个接口 13、extends和implements可以共存,extends在前,implements在后 14、使用接口写代码的时候,可以使用多态(父类型引用指向子类型对象) 15、接口的使用离不开多态机制(因为接口是完全抽象类无法创建对象 多态刚好父类型引用指向子类型对象)
public class homework01 {
public static void main(String[] args) {
// 访问接口常量
System.out.println(A.PI); // 3.15159
// 常量能重新赋值吗? 不能:因为常量被final修饰了
// A.PI =3.1415926; // 报错:无法为最终变量PI分配值
}
}
// 定义接口
interface A{
// 常量
// public static final double PI =3.14159;
// 接口当中既然都是常量,那么public static final 能不能省略? 答案:可以
double PI =3.14159; // 写一个常量编译器发现是接口也会把变量当成常量 public static final double PI
// 接口中随便写一个变量就是常量【常量:值不能改变的变量】
// 抽象方法
// public abstract int sum(int a,int b);
// 接口当中既然都是抽象方法,那么在编写代码的时候,可不可以把public abstract省略? 答案: 可以
int sum(int a,int b);
}
// 接口支持继承
interface B extends A{
}
// 接口支持多继承
interface C extends A,B{}
二、接口的基础语法
public class homework01 {
public static void main(String[] args) {
// 能使用多态吗? 可以
// 父类型的引用指向子类型的对象[子类为“非抽象”类 所以可以创建对象]
MyMath mm =new MyMathImPm();
// 调用接口里面的方法(面向接口编程)
// mm.sum(参数);
// 编译时: 先在父类MyMath当中绑定sum方法
// 运行时: 在子类MyMathImPm当中找到sum方法进行运行
System.out.println(mm.sum(10,30)); // 40
System.out.println(mm.sub(90,40)); // 50
}
}
// 接口(完全抽象的类 叫做接口)
interface MyMath{
// 常量 public static final double PI =3.1415926;
double PI =3.1415926;
// 抽象方法 public abstract int sum();
int sum(int a,int b);
int sub(int a,int b);
}
// 编写一个MyMathImPm类(这个类是一个"非抽象"类)
/*
class MyMathImPm implements MyMath{
// 注意: 方法体当中不写任何代码的话会报错:因为MyMathImPm这个类是“非抽象”类,而实现(继承)的类为抽象类 继承的方法为抽象方法
// 而抽象方法必须在抽象类当中 所以报错:MyMathImPm不是抽象的, 并且未覆盖MyMath中的抽象方法sum(int,int)
}
*/
// 修正
class MyMathImPm implements MyMath{
// 重写/覆盖/实现 接口中的方法(通常叫做实现)
public int sum(int a,int b){
// 因为为int型方法所以要有返回值
return a+b;
}
public int sub(int a,int b){
return a-b;
}
/*
思考: 能不能把方法中的public去掉?
答案:不能 报错:正在尝试分配更低的访问权限; 以前为public[接口当中所有抽象方法都是public修饰的,继承下来的话不能将访问权限降低]
int sum(int a,int b){
return a+b;
}
*/
}
三、一个类可以实现多个接口
一个类可以实现(继承)多个接口 这种机制弥补了java中的哪个缺陷? java中类和类只支持单继承,实际上单继承是为了简单而出现的,现实世界中存在多继承,java中的接口弥补了单继承带来的缺陷
public class homework01 {
public static void main(String[] args) {
// 多态该怎么用呢?
// 都是父类型引用指向子类型对象
A a =new D(); // 【向上转型】
B b =new D();
C c =new D();
// 思考: a.m2(); 怎么实现【m2在B抽象类当中 而a为A抽象类 A与B抽象类没有继承关系】
// 强制转换【向下转型】
B b2 =(B)a;
b2.m2(); // 输出结果:m2.....
}
}
/*
// 接口和接口支持多继承
interface X{
}
interface Y{
}
interface Z extends X,Y{
}
*/
// 一个“非抽象”类可以实现多个接口
interface A{
void m1();
}
interface B{
void m2();
}
interface C{
void m3();
}
class D implements A,B,C{
public void m1(){
System.out.println("m1.....");
}
public void m2(){
System.out.println("m2.....");
}
public void m3(){
System.out.println("m3.....");
}
}
四、extends 和 implements关键字同时存在时
继承和实现都存在的话,代码应该怎么写? extends 关键字在前 implements 关键字在后
public class homework01 {
public static void main(String[] args) {
// 创建对象(表面看Animal类没起作用:先不用管)
Flyable f1 =new Cat(); // 多态
f1.fly();
Flyable f2 =new Pig();
f2.fly();
Flyable f3 =new Fish();
f3.fly();
}
}
// 动物类: 父类
class Animal{
}
// 可飞翔的接口(是一对翅膀)
interface Flyable{
// 飞翔的抽象方法
void fly();
}
// 动物类:子类
// Flyable是一个接口,是一对翅膀的接口,通过接口插到猫身上,让猫可以飞翔
class Cat extends Animal implements Flyable{
// 当“非抽象”类Cat实现[实现:可以理解为继承]“完全抽象”类Flyable时候 需要重写方法
public void fly(){
System.out.println("飞猫起飞,翱翔太空的一只猫,很神奇,我想做一只猫~");
}
}
// 狗类: 如果你不想让它起飞,可以不实现Flyable接口
// 没有实现这个接口表示你没有翅膀,没有给你翅膀,你肯定不能飞
class Dog extends Animal{
}
// 想飞就给翅膀这个接口
class Pig extends Animal implements Flyable{
public void fly(){
System.out.println("我是一只会飞的猪~");
}
}
// 鱼 (没写继承,默认实际上是存在继承的,默认继承object类)
// class Fish extends object implements Flyable{}
class Fish implements Flyable{ // 没写extends继承时默认继承object类
public void fly(){
System.out.println("我是六眼飞鱼(流言蜚语)~");
}
}
运行结果:
五、接口在开发中的作用
面向抽象编程这句话以后可以改为:面向接口编程
分析:
中午去饭馆吃饭,这个过程有接口吗?
接口是抽象的
菜单是一个接口(菜单上有一个抽象的图片:西红柿炒鸡蛋)
谁面向这个接口?(顾客面向菜单点菜,调用接口)
谁负责实现这个接口呢?(后厨的厨师负责把西红柿炒鸡蛋做好,是接口的实现者)
这个接口有什么用呢?
这个饭馆的“菜单”,让“顾客”和“厨师”解耦合了
顾客不用找后厨,后厨不用找顾客,他们之间完全依靠抽象的“菜单”沟通
菜单 接口 抽象的
// 菜单 接口 抽象的
public interface FoodMenu {
// 西红柿炒鸡蛋 抽象方法
void xiHongShiChaoJiDan();
// 鱼香肉丝
void yuRouSi();
}
厨师
// 西餐厨师
// 实现菜单上的菜
// 厨师是接口的实现者
public class AmericCooker implements FoodMenu{
// 西红柿炒鸡蛋
public void xiHongShiChaoJiDan(){
System.out.println("西餐厨师做的西红柿炒鸡蛋");
}
// 鱼香肉丝
public void yuRouSi(){
System.out.println("西餐厨师做的鱼香肉丝");
}
}
// 中餐厨师
// 实现菜单上的菜
// 厨师是接口的实现者
public class ChinaCooker implements FoodMenu {
// 西红柿炒鸡蛋
public void xiHongShiChaoJiDan(){
System.out.println("中餐厨师做的西红柿炒鸡蛋");
}
// 鱼香肉丝
public void yuRouSi(){
System.out.println("中餐厨师做的鱼香肉丝");
}
}
顾客
// 顾客
public class Customer {
// 顾客手里有一个菜单
// Customer has a FoodMenu(这句话的意思:顾客有一个菜单)
// 记住: 凡是能够使用 has a 来描述的,统一以属性(变量)的方式存在
// 实例变量 属性
// 面向抽象编程,面向接口编程,降低程序的耦合度,提高程序的扩展力
private FoodMenu foodMenu; // 要养成封装的好习惯 [相当于把FoodMenu类交给foodMenu引用]
/*
如果以下这样写就表示写死了 表明顾客只能吃西餐或者中餐,【耦合度高了,扩展力差】
【FoodMenu是一个更抽象的父类型 ChinaCooker,AmericCooker都已经实现了FoodMenu】
中餐厨师
ChinaCooker cc;
西餐厨师
AmericCooker ac;
*/
// 提供一个点菜的方法
public void order(){
// 先拿到菜单才能点菜
FoodMenu fm =this.getFoodMenu(); // FoodMenu相当于类型(String int double...)
fm.xiHongShiChaoJiDan();
// 也可以不用get方法,因为在本类中私有的属性是可以直接访问[私有属性当中刚好把菜单类赋给了引用foodMenu]
// foodMenu.yuRouSi();
}
// 构造方法
public Customer() {
}
public Customer(FoodMenu foodMenu) {
this.foodMenu = foodMenu;
}
public FoodMenu getFoodMenu() {
return foodMenu;
}
public void setFoodMenu(FoodMenu foodMenu) {
this.foodMenu = foodMenu;
}
}
代码测试
public class ImplementsTest {
public static void main(String[] args) {
// 创建厨师对象
FoodMenu cooker1 =new ChinaCooker(); // 因为ChinaCooker实现了FoodMenu,相当于cooker1引用还是指向了菜单FoodMenu类
// 创建顾客对象
Customer customer =new Customer(cooker1); // 传的相当于是菜单
// 顾客点菜
customer.order();
}
}