接口也是一种引用数据类型 。编译之后也是一个class字节码文件。
接口是完全抽象的。(抽象类是半抽象) 或者也可以说接口是特殊的抽象类。
接口怎么定义的,语法是什么?
[修饰符列表] interface 接口名{}
接口支持多继承,一个接口可以继承多个接口。
一般情况下接口只包含两部分内容。一部分是:常量,一部分是:抽象方法。
一般情况下接口中的所有元素都是public修饰的。(都是公开的。)
接口中的抽象方法定义时:public abstract修饰符可以省略。
接口中定义常量时:public static final 可以省略。
一般情况下接口中的方法都是抽象方法,所有接口中的方法不能有方法体。
public class Test01{
public static void main(String[]args){
//访问接口的常量
System.out.println(MyMath.PI);
//错误: 无法为最终变量PI分配值
//MyMath.PI=3.1415928;
}
}
//我的数学接口
interface MyMath{
//常量
// public static final double PI=3.1415926;
//接口中public static final 可以省略 如:
double PI=3.1415926;
//再如:
int k=100; //接口中随便写一个变量就是常量:值不能发生改变的变量。
//抽象方法
//接口中既然都是抽象方法,那么public abstract在编写时可以省略
//public abstract int sum(int a,int b);
int sum(int a,int b);
// 接口抽象方法不能带有主体
// void dosome(){} 错误
//相减的抽象方法
int sub(int a,int b);
}
//定义接口
interface A{
public abstract void methodA();
public abstract void methodCommon();
public default void methodDefault(){
System.out.println("接口A默认方法");
}
}
//定义接口
interface B{
public abstract void methodB();
public abstract void methodCommon();
public default void methodDefault(){
System.out.println("接口B默认方法");
}
}
//定义接口 接口可继承接口 支持多继承
//这个接口中有4个方法
/*
methodA():来自于接口A
methodB():来自于接口B
methodCommon():同时来自于接口A,B
methodA():来自于自己
*/
interface C extends A,B{
public abstract void method();
//重写重复的默认方法
@Override
default void methodDefault() {
}
}
类和类之间叫做继承,类和接口之间叫做实现。(仍然可以将实现看做’继承’)
继承关键字:extends。
实现关键字:implements
当一个非抽象的类实现接口的话,必须重写接口中所有的抽象方法。重写后方法的修饰符必须为public,若方法名重复,重写一次即可。
如果实现类没有覆盖重写所有接口当中的所有抽象方法,那么实现类必须是一个抽象类。
一个类可以同时实现多个接口。java中的接口弥补了单继承带来的缺陷。
当运用多态创建对象,调用其他接口可能会出现的问题:
如下(类实现多接口演示中),接口K和M虽然没有继承关系,但编写代码的时候,可以互转。编译器没意见,但是运行时可能出现ClassCastException异常。
之前有一个结论:
无论向上转型还是向下转型,两种类型之间必须要有继承关系,没有继承关系,编译器会报错。(但这句话不适用在接口方面)。但实际上和之前还是一样,需要:if+instanceof运算符进行判断。
public class Test02{
public static void main(String[]args){
//使用多态
MyMath m=new MyMathImpl();
System.out.println( m.sum(10,9));
System.out.println( m.sub(10,9));
}
}
//数学接口
interface MyMath{
double PI=3.1415926;
//求和方法
int sum(int a,int b);
//相减方法
int sub(int a,int b);
}
//实现数学接口的类
class MyMathImpl implements MyMath{
//错误:正在尝试分配更低的访问权限:以前为public
/*
int sum(int a,int b){
return a+b;
};
*/
//重写接口中方法
//求和方法
public int sum(int a,int b){
return a+b;
};
//相减方法
public int sub(int a,int b){
return a-b;
};
}
//接口与接口支持多继承
/*
interface X{}
interface Y{}
interface Z extends X,Y{}
*/
//-----------------------------------------------------
//类实现多接口
public class Test03{
public static void main(String[]args){
//多态使用
A a=new D();
B b=new D();
C c=new D();
//不能直接去调用其他接口方法
// a.m2();
//这个编译没问题 运行也没问题
B b2=(B)a;
b2.m2();
// M m=new E();
//经过测试:接口和接口之间在进行强制类型转化的时候,没有继承关系,也可以强转。
//但一定要注意:运行时可能会出现ClassCastException(类型转化)异常。
//要先用instanceof 判断
//if(m instanceof K){ K k=(K)m;}
}
}
//-----------------------------------------------------
interface K(){}
interface M(){}
class E implements M{
}
//-----------------------------------------------------
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(){};
}
从java8开始接口允许定义默认方法。
格式:(public可省略)
public default 返回值类型 方法名称(参数列表){方法体}
备注:接口中默认方法可以解决接口升级问题。
如:
当一些类实现接口后,若接口中新增抽象方法,这些实现类必须得去重写接口中的新增方法,从而导致项目中代码需整体改动,可能引发错误。
接口的默认方法:可以通过接口实现类对象,直接调用。
接口的默认方法:也可以被接口实现类进行覆盖重写。如果实现类实现多个接口中,存在重复的默认方法,那么实现类一定要对冲突的默认方法进行覆盖重写。
//测试类
class Test {
public static void main(String[] args) {
//多态 向上转型
MyInterfaceDefault m=new MyInterfaceDefaultA();
MyInterfaceDefaultB m1=new MyInterfaceDefaultB();
//调用MyInterfaceDefaultA中methodAbs方法
m.methodAbs();//MyInterfaceDefaultA
//可从接口里直接调用
m.methodDefault;//新添加的默认方法
System.out.println("==============");
m1.methodAbs(); //MyInterfaceDefaultB
//调用重写的methodDefault方法
m1.methodDefault();//实现类B覆盖重写了接口的默认方法
}
}
public interface MyInterfaceDefault {
//抽象方法
public abstract void methodAbs();
//新添加了一个抽象方法 MyInterfaceDefaultA和MyInTerfaceDefaultB去重写该方法
// public abstract void methodAbs1();
//新添加的方法,改成默认方法
public default void methodDefault(){
System.out.println("新添加的默认方法");
}
}
class MyInterfaceDefaultA implements MyInterfaceDefault{
@Override
public void methodAbs() {
System.out.println("MyInterfaceDefaultA");
}
}
class MyInterfaceDefaultB implements MyInterfaceDefault{
@Override
public void methodAbs() {
System.out.println("MyInterfaceDefaultB");
}
@Override
public void methodDefault() {
System.out.println("实现类B覆盖重写了接口的默认方法");
}
}
从java8开始 接口中允许定义静态方法。
格式:
public static 返回值类型 方法名称(参数列表){
方法体;
}
提示:就是将abstract或者default换成static即可,带上方法体。
注意:不能通过接口实现类的对象调用接口中的静态方法
正确写法:通过接口名称,直接调用其中的静态方法
接口名称.静态方法名(参数)
//测试类
class Test02{
public static void main(String[] args) {
//创建实现类对象
MyInterfaceStaticImpl m=new MyInterfaceStaticImpl();
//错误写法
//不能通过接口实现类的对象调用接口中的静态方法
// m.methodStatic();
//直接用接口调用
MyInterfaceStatic.methodStatic//输出:这是接口的静态方法!
}
}
//接口
public interface MyInterfaceStatic {
public static void methodStatic(){
System.out.println("这是接口的静态方法!");
}
}
//实现类
class MyInterfaceStaticImpl implements MyInterfaceStatic{
}
使用场景:当编写接口的默认或静态方式时,可能会出现一些重复代码,为了使代码简洁,我们需要抽取一个公有方法,用来解决两个默认方法之间重复代码的问题,但是这个共有方法不应该让实现类使用,应该私有化的。
解决方案:
从java9开始,接口中允许定义私有方法
//测试类
class Test03{
public static void main(String[] args) {
//多态
MyInterfacePrivateA m=new MyInterfacePrivateAImpl();
m.methodDefault1();
MyInterfacePrivateAImpl m1=new MyInterfacePrivateAImpl();
m1.methodDefault2();
}
}
//接口
public interface MyInterfacePrivateA {
public default void methodDefault1(){
System.out.println("这是一个默认方法1");
//直接调用methodCommon()
methodCommon();
}
public default void methodDefault2(){
System.out.println("这是一个默认方法2");
//直接调用methodCommon()
methodCommon();
}
//私有的公有方法
private void methodCommon(){
System.out.println("AAA");
System.out.println("BBB");
System.out.println("CCC");
}
}
//实现类
class MyInterfacePrivateAImpl implements MyInterfacePrivateA{
public void methAnother(){
//若接口的共有方法不是private,可直间访问到接口中的默认方法
//methodCommon();
}
}
//测试类
class Test04{
public static void main(String[] args) {
MyInterfacePrivateB m=new MyInterfacePrivateAImplB();
//不能通过接口实现类的对象调用接口中的静态方法
//m.methodDefault1();
//直接用接口调用
MyInterfacePrivateB.methodDefault1();
MyInterfacePrivateB.methodDefault2();
}
}
//接口
public interface MyInterfacePrivateB {
public static void methodDefault1(){
System.out.println("这是一个静态方法1");
methodCommon();
}
public static void methodDefault2(){
System.out.println("这是一个静态方法2");
methodCommon();
}
private static void methodCommon(){
System.out.println("AAA");
System.out.println("BBB");
System.out.println("CCC");
}
}
//实现类
class MyInterfacePrivateAImplB implements MyInterfacePrivateB{
public void methAnother(){
//若接口的共有方法不是private,可直间访问到接口中的默认方法
//MyInterfacePrivateB.methodCommon();
}
}
//测试类
class Test05{
public static void main(String[] args) {
Son s=new Son();
s.method();//输出:父类的方法
}
}
//父类
public class Fu {
public void method(){
System.out.println("父类方法");
}
}
//接口
interface Inf{
//默认方法
public default void method(){
System.out.println("接口方法");
}
}
//子类
class Son extends Fu implements Inf{
}
接口在开发中的作用,类似于多态在开发中的作用。
多态:面向抽象编程,不要面向具体编程。降低程序的耦合度,提高程序的扩展力。
如:
public class Master{
public void feed(Dog d){};
public void feed(Cat x){};
}
//假设又要养其他宠物,那么这时候需要再加1个方法。(修改代码)
//这样扩展力太差了,违背了OCP原则(对扩展开放,对修改关闭)
改为:
public class Master{
public void feed(Animal a){};
}
//面向Animal父类编程,父类比子类更抽象的,这样程序扩展力就更强
面向接口编程,可以降低程序的耦合度,提高程序的扩展力,符合OCP开发原则。
接口的使用离不开多态机制。(接口+多态才可以达到降低耦合度)。
任何接口都有调用者和实现者。接口可以将调用者和实现者解耦。
调用者面向接口调用。
实现者面向接口编写实现。
// 菜单 接口
public interface FoodMenu{
//西红柿炒蛋
void shizichaojidan();
//鱼香肉丝
void yuxiangrousi();
}
// 中国厨师 实现者
public class ChinaCooker implements FoodMenu{
public void shizichaojidan(){
System.out.println("中国厨师做了一个西红柿炒鸡蛋")
}
public void yuxiangrousi(){
System.out.println("中国厨师做了一个鱼香肉丝")
}
}
// 美国厨师 实现者
public class AmericCooker implements FoodMenu{
public void shizichaojidan(){
System.out.println("美国厨师做了一个西红柿炒鸡蛋")
}
public void yuxiangrousi(){
System.out.println("美国厨师做了一个鱼香肉丝")
}
}
// 消费者 调用者
public class Customer{
//面向接口编程
private FoodMenu foodMenu;
//有参构造
public Customer(FoodMenu foodMenu){
this.foodMenu=foodMenu;
}
//无参构造
public Customer(){
}
//get 方法
public FoodMenu getFoodMenu(){
return foodMenu;
}
//set 方法
public void setFoodMenu(FoodMenu foodMenu){
this.foodMenu=foodMenu;
}
//提供一个点餐方法
public void order(){
//用get方法调用
// FoodMenu fm=this.getFoodMenu();
// fm.shizichaojidan();
//fm.yuxiangrousi();
foodMenu.shizichaojidan();
foodMenu.yuxiangrousi();
//实现一个静态代理
System.out.println("点餐结束");
}
}
//测试类
public class Test06{
public static void main(String[]args){
//创建厨师对象
FoodMenu cooker1=new ChinaCooker();
//创建顾客对象
Customer customer=new Customer(cooker1);
//顾客点餐
customer.order();//输出:中国厨师做了一个西红柿炒蛋
// 中国厨师做了一个鱼香肉丝
// 点餐结束
}
}
本文地址:https://blog.csdn.net/MTCya/article/details/107346760
如对本文有疑问, 点击进行留言回复!!
网友评论