如果一个抽象类中所有的方法都是抽象方法 那么这就相当于接口,接口与类支持多实现、接口与接口支持多继承,所以接口不是类
如果不想重写接口中所有的抽象方法就可以把实现接口的类变成抽象类
//接口与接口之间支持多继承,继承的也是接口 interface B extends C,Cloneable{ public abstract void m(); } interface C{ public abstract void n(); } //implements用于表示类与类之间的关联关系 -----实现 //java支持类的多实现,一个类可以实现多个接口 class A implements B,C{ @Override public void m() { // TODO 自动生成的方法存根 } @Override public void n() { // TODO 自动生成的方法存根 } }
接口中一定有抽象方法?(jdk1.7及以前是一定的,jdk1.8及其以后就是不一定的)
接口是单继承(实现)还是多继承(实现)? 都可以,多实现提高代码的复用性,但是还是会有同名方法的混用问题,所以要看场景
类与类之间的关系是单继承----树状结构---关系判断迅速
类与接口,接口与接口之间是多实现和多继承---网状结构
在网状这种结构下,想要去确定两个对象之间的关系很难去确定
而且编译时期和运行时期都要去确定,都是比较麻烦的所以Java就规定接口在编译时期就不用去检测对象声明类之间的关系
直接通过,在运行时期再去实际的检测,如果检测类型之间是否有实现关系 ,不是就报错,如果是就通
接口类型可以接收所有类型的值的转换。只要实现了接口
public class Error2 {
public static void main(String[] args) { A2 a=new B2(); //向上转型 /** * 编译时期会检测两个对象的声明类是否有继承关系 * 如果有继承关系就编译通过 b的声明类是B2 a的声明类是A类有继承所以不报错 * 运行时期会检测两个对象的实际创建类是否相等 * 如果相等或者右边的实际创建类是要转换类的子类就运行通过 b的实际创建类时B2,a的实际创建类是B2 */ B2 b=(B2)a; //正确的 /** * d的声明类是D a的声明类是A2 有继承关系所以编译不报错 * d的实际创建类是D,a的实际创建类是B2 不一样就运行报错 */ // D d=(D)a;//正确的A2 a2=(A2)b; a2的声明类是A2 b的声明类是B2 有继承关系所以编译不报错, a2的实际创建类是A2 b的实际创建类是B2 B2是A2的子类所以运行时期可以通过
//接口 //编译的时候针对任意对象都没错,运行时期有错 E e=(E)b; e=(E)a; System.out.println("成功的"); } } class A2{ } class B2 extends A2{ } class D extends A2{ } interface
接口中可以定义属性和抽象方法吗?
属性默认被public static final 修饰 都是默认修饰
抽象方法会被public、abstract共同修饰 都是默认修饰
接口的作用 -------相当于模板
接口不能创建对象 ---------因为接口中不能含有构造方法 ,IE e; e不是IE这个接口的对象,只是接口声明的对象,可以调用接口的方法。
JDK1.8新特性
1.jdk1.8以前接口中都要是抽象方法,从jdk1.8开始允许。接口可以有实体方法 加上defalut或者static ,default 修饰的默认实体方法,static修饰的静态实体方法
//计算器 interface calc{ //抽象方法 //int sum(int x,int y); //实体方法 加上default 方法就变成了实体方法 public default int sum(int x,int y,int z) { return x+y+z; } //加上static可以实现实体方法 public static int mul(int x,int y) { return x*y; } int max(int x,int y); }
default修饰的接口实体方法可以重写 ,static 不能重写
2.Lambda表达式-----去重写接口中的抽象方法,这样就不用具体类实现接口了,他是针对接口中只有一个抽象方法,可以有多个实体方法
而一个接口只有一个抽象方法 有注解FunctionalInterface
@FunctionalInterface interface c{ public default void name() { } public abstract void m(); }
c不是接口的对象,接口没有对象,c只是接口声明的对象,用来调用接口中的方法
//Lambda表达式---(参数列表)-->{重写抽象方法的方法体} calc c=(int x,int y)->{return x>y?x:y;}; System.out.println(c.max(10, 20));
如果重写抽像方法的方法体只有一句话就可以省略return 和大括号
calc c=(int x,int y)->x>y?x:y;
如果参数列表的数据类型在抽象方法中已经明确(这个应该是根据参数的个数判断的),Lambda表达式就可以通过前面的这个数据类型进行推导
calc c=(x,y)->x>y?x:y;
案例2
public class Error2 { public static void main(String[] args) { int[] arr=new int[] {2,5,86,3,1,2}; //lambda表达式实现接口排序方法 //Array a=(int[] arr1)->{Arrays.sort(arr1);}; //因为方法体中是一条语句所以{}和return 可以省略 //Array a=(int[] arr1)->Arrays.sort(arr1); //数据类型可以由抽象方法的参数数据类型进行推导 //Array a=(arr1)->Arrays.sort(arr1); //因为只有一个参数所以()也可以省略 //Array a=arr1->Arrays.sort(arr1); //当从头到尾就只有一个参数参与而且可以从抽象方法中获取 //::的意思是 "的"意思 ---传递的是静态方法 Array a =Arrays::sort; //测试 a.arraySort(arr); System.out.println(Arrays.toString(arr)); } } //数据排序接口 interface Array{ void arraySort(int[] arr); }
接口的优点:1.可以做约束也可以当模板
2.向上造型的类型统一