一.接口
接口就是用来规范方法的,接口是方法的模板
接口(硬件类接口)是指同一计算机不同功能层之间的通信规则称为接口。
接口(软件类接口)是指对协定进行定义的引用类型(类,数组,接口)。其他类型实现接口,以保证它们支持某些操作。接口指定必须由类提供的成员或实现它的其他接口。与类相似,接口可以包含方法、属性、索引器和事件作为成员。
接口是一个特殊的Java类,接口可以做到多继承(接口的继承称为实现,接口可以多实现)
1.基本接口
(1)接口的定义,声明
Java类使用的是class关键字,接口使用interface关键字声明。
语法:public interface 接口的名字{ }
类中有属性;方法:有参构造和普通;代码块:静态代码块和普通代码块;普通方法:静态和非静态,有参无参,有返回值和无返回值
a.属性
在反编译工具中,我们可以看到接口中的属性默认是使用public static final修饰的
接口是一个特殊的类,接口不能自己实例化自己
使用final修饰的属性称为常量,要手动赋予初始值,声明的时候赋值(全局变量)
usb是一个接口,不能直接实例化
b.方法
没有代码块、没有静态代码块、没有构造方法、普通方法 、最终方法
可以有静态方法,抽象方法(默认抽象方法是使用public abstract修饰的),默认方法
抽象方法:使用abstract关键字修饰的没有方法体{}的方法称为抽象方法
默认方法(jdk1.8之后才有的)
总结接口中的规定:
接口中只能有静态方法(因为静态方法不需要实例化对象)和抽象方法(抽象方法没有方法体:没有具体的执行代码)
接口不能自己像普通类一样直接new自己
接口中的属性都是公共静态常量(public static final), 必须在声明的时候赋予初始值
2.接口如何使用
在开发中大多使用抽象方法
接口的实例化是使用已知实现子类,采用多态思想来实例化对象
a.接口的实现
使用 implements 关键字来实现接口(实现接口的子类必须重写该接口的所有
抽象方法同时必须有具体的方法体)
一个子类可以同时实现多个接口 多个接口使用,(逗号)分割
接口可以继承接口
一个类既可以继承一个父类 也可以同时实现多个接口
b.接口的具体调用
调用静态方法
c.使用匿名对象的写法来调用
匿名对象就是实例化一个对象 没有具体的引用。匿名对象只能使用一次,不能被重复使用。
接口可以实例化自己,在实例化的时候 使用 new 接口名(){ 重写并实现接口中的所有抽象方法 }
//匿名对象调用接口方法
@Test
void test03() {
//使用匿名对象调用普通类的方法
//如果在操作中,只需要一次该对象就可以使用匿名对象,如果用多次,那还是实例化对象比较方便
Phone phone=new Phone();//该实例化的对象被phone所引用,phone来重复使用该对象
phone.chongdian();
new Phone().chongdian();//匿名对象的调用
//在接口中使用匿名对象(不考虑静态方法)剩下的都是抽象方法
//抽象方法没有具体的方法实现(方法体)
//使用匿名对象实例化接口,必须重写并实现接口中的所有抽象方法new Usb() {重写并实现抽象方法}.chongdian();
//接口直接实现接口
new Usb() {
@Override
public void chongdian() {
// TODO Auto-generated method stub
System.out.println("接口自己实例化自己,重写的连接方法");
}
//重写该接口的抽象方法(Android)
@Override
public void chuanshu() {
// TODO Auto-generated method stub
System.out.println("接口自己实例化自己,重写的数据传输方法");
}
}.chongdian();
}
@Test
void test04() {
Usb usb=new Usb() {
@Override
public void chongdian() {
// TODO Auto-generated method stub
System.out.println("接口自己实例化自己,重写的连接方法");
}
//重写该接口的抽象方法(Android)
@Override
public void chuanshu() {
// TODO Auto-generated method stub
System.out.println("接口自己实例化自己,重写的数据传输方法");
}
};
usb.chongdian();
}
接口可以使用多态的思想 用自己的已知实现子类来实例化自己。 最终调用接口的方法其实就是调用已知实现子类重写的方法。
//使用多态来实例化接口对象调用方法,其实调用的是子类的具体操作
@Test
void test02() {
//实例化接口(多态:父类引用指向子类对象)
Usb usb=new Phone();
usb.chongdian();//手机充电
Android usb2=new Phone();
usb2.chuanshu();//使用数据线进行传输
Usb usb1=new Upan();
usb1.chongdian();//U盘进行数据传输
}
接口的作用 : 接口是用来做方法的规定的。具体要根据最终实现自己的子类来决定具体应该怎么做。 一定要使用多态的思想。
子类实现了父类接口,必须要重写并实现接口中的所有的抽象方法
接口所在的包是dao包,接口的实现类所在的包叫 dao.imp
2.函数式接口
有且只有一个抽象方法的接口称为函数式接口。
使用注(是一个特殊的Java类)@FunctionalInterface来判断该接口是不是函数式接口
(1) 声明并验证
@FunctionalInterface//来判断该接口是不是函数式接口
public interface FunInter {
void eat();//被public abstract 修饰
}
(2)使用
a.原始用法
使用已知实现子类
使用匿名对象的写法:new 接口名字(){重写抽象方法}
b.lambda表达式的用法(1.8新特性的使用方法)
Lambda 表达式 主要是1.8jdk中为了简化对函数式接口的实例化操作
语法:函数式接口类型变量 = (参数... ) -> { 重写的方法中的具体执行代码 };
()在参数只有一个的情况下可以省略
{ } 在方法中只有一条执行代码的时候{} 省略
参数可以不指定类型
package com.xing.yun.fun;
@FunctionalInterface//来判断该接口是不是函数式接口
public interface FunInter {
//没有参数没有返回值
void eat();//被public abstract 修饰
}
@FunctionalInterface
interface FunInter01 {
//有参数没有返回值
void eat(int a,int b);
}
@FunctionalInterface
interface FunInter02 {
//没有参数有返回值
int eat();
}
@FunctionalInterface
interface FunInter03 {
//有参数有返回值
int eat(int a,int b);
}
@FunctionalInterface
interface FunInter04 {
//有一个参数没有返回值
int eat(int a);
}
使用junit进行测试
package com.xing.yun.fun;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
//普通对象可以被重复调用,匿名对象只能使用一次
class FunInterTest {
//普通匿名对象方式来实例化函数式接口
@Test
void test() {
//实例化对象
new FunInter() {
@Override
public void eat() {
//TODO Auto-generated method stub
System.out.println();
}
}.eat();
}
//函数式接口的lambda表达式的实例化调用
@Test
void test01() {
//实例化接口对象
FunInter fi = () -> {System.out.println("我什么也不想吃");};
fi.eat();
}
//两个参数的方法,()里面的参数相当于形式参数
@Test
void test02() {
//实例化接口对象()中的参数为重写抽象方法之后的形式参数
FunInter01 fi = (int a,int b) -> {System.out.println(a+b);};
FunInter01 fi1 = (num1,num2) -> {System.out.println(num1+num2);};
//调用方法,就是调用lambda表达式重写之后的方法
fi.eat(10,20);
fi1.eat(10,20);
}
//没有参数有返回值
@Test
void test03() {
//实例化接口对象
FunInter02 fi = () -> {return 100;};
FunInter02 fi1 = () -> 100;
System.out.println(fi.eat());
System.out.println(fi1.eat());
}
//有参有返回值
@Test
void test04() {
//实例化接口对象
FunInter03 fi = (a,b) -> {
int num=a+b;
return num;
};
System.out.println(fi.eat(10,20));//实参类型是接口中的实参类型规定的
}
//一个参数
@Test
void test05() {
//实例化接口对象 1--100的总和
FunInter04 fi = (int a) -> {
int sum=0;
for(int i = a; i <= 100; i++) {
sum=sum+i;
}
return sum;
};
System.out.println(fi.eat(1));
}
}
接口与类相似点:
一个接口可以有多个方法。
接口文件保存在 .java 结尾的文件中,文件名使用接口名。
接口的字节码文件保存在 .class 结尾的文件中。
接口相应的字节码文件必须在与包名称相匹配的目录结构中。
接口与类的区别:
接口不能用于实例化对象。
接口没有构造方法。
接口中所有的方法必须是抽象方法。
接口不能包含成员变量,除了 static 和 final 变量。
接口不是被类继承了,而是要被类实现。
接口支持多继承。
接口特性
接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
重写接口中声明的方法时,需要注意以下规则:
类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。
类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型。
如果实现接口的类是抽象类,那么就没必要实现该接口的方法。
在实现接口的时候,也要注意一些规则:
一个类可以同时实现多个接口。
一个类只能继承一个类,但是能实现多个接口。
一个接口能继承另一个接口,这和类之间的继承比较相似。