接口
接口是什么?
用 interface 关键字定义的一个只有方法名,没有方法体的一个域就是接口。
当我们要实现接口的功能时,我们需要用到 implement 关键字。
为什么要用接口?
我们在工程里面会遇到这样的难题,有很多类都需要一个相同的方法或者变量,如果要相互调用非常麻烦,我们需要去实例化,或者继承关系或者抽象成抽象类等等等,但是如果定义成一个接口,那么所有的类都可以使用它并且还可以写入合适的方法。
接口的特征有哪些呢???
- 不能使用new操作符去创建对象
- 实现类必须重写接口的所有方法,反之,就将该实现类定义为一个抽象类
- 类可以继承多个接口,多继承
- 接口当中成员变量都是public static final,成员方法都是public
- 接口当中的方法都是只有方法的声明而没有方法体
- java8(jdk1.8)之后新添加的两个特性
- default关键字可以定一个default方法,有方法的实现
- 可以定义static的静态方法,有方法的实现
现在我们来实现一下:
interface InterfaceName1{ //接口一
int index = 0;//默认修饰符为public static final
public void func(); //接口的方法只能有方法名,不能有方法体
public default void run(){ //JDK1.8之后的特性,可以有方法体的方法,但必须用default去修饰
System.out.println("新特性方法");
}
public static int getVaule(){ //1.8新特性,可以有静态方法
return 1;
}
}
interface InterfaceName2{ //接口二
int index = 0;//默认修饰符为public static final
public void func();
}
class A implements InterfaceName1, InterfaceName2{ //接口特性:多实现
@Override
public void func() {
//System.out.println(index);
}
}
我们现在可以发现一个问题,func()方法中打印的 index 到底是接口一还是接口二的??
这就是static关键字的用处了,我们可以直接用接口名去实现
并且接口是可以作为参数使用的
我们现在把接口作为参数,实现加减乘除功能。
interface Caculator{ //计算器接口
public int caculate(int first, int secnd); //加 减乘除都是两个数做运算
}
//实现加法
class Add implements Caculator { //用一个类实现这个接口的方法
@Override
public int caculate(int first, int secnd) {
return first + secnd;
}
}
//实现减法
class Sub implements Caculator{
@Override
public int caculate(int first, int secnd) {
return first - secnd;
}
}
//实现乘法
class Mul implements Caculator{
@Override
public int caculate(int first, int secnd) {
return first * secnd;
}
}
//实现除法
class Div implements Caculator{
@Override
public int caculate(int first, int second) {
if(second == 0){
return -1;
}
return first/second;
}
}
public static void caculate1(Caculator ca, int first, int secend){ //把接口定义成参数,
//因为我们无法去实例化一个接口,
//所以我们必须要实例化实现接口的类
System.out.println( ca.caculate(first,secend)) ; // 调用具体类实现的接口种的方法
}
public static void main(String[] args){
caculate1(new Add() , 12,12); //第一个参数我们实例化实现接口的类
caculate1(new Sub() , 12,12);
caculate1(new Mul() , 12,12);
caculate1(new Div() , 12,12);
}
结果:
抽象类
抽象类是什么?
abstract 关键字修饰的方法叫做抽象方法,包含抽象方法的的类叫做抽象类,并且该类必须用abstract关键字修饰
为什么要用到抽象类??
无法实现具体方法,需要多态(继承,重写,向上转型)
例如,一个图形类,我们给他一个求面积方法,但是每个形状求面积的方法都是不一样的,我们没有办法给出具体的方法体,所以我们需要让他的派生类(也就是子类)去重写这些抽象方法,去具体化的操作,也就是我们所说的多态,这样我们才能根据具体是实例去实现对应的方法。
那么在使用抽象类时我们需要注意什么呢??
1有抽象方法的类必须是抽象类,抽象类可以有抽象方法, 也可以有非抽象方法
2)抽象类不能new对象
3)一般来讲,抽象类的构造函数声明为protected,因为都是子类去实现,
4)当我们去用一般类去实现抽象类的时候,我们需要实现抽象类所有的抽象方法
5)抽象类无法被实例化,所以我们必须运用向上造型,才能调用抽象类(也就是父类)中的一般方法
那我们来实现一下抽象类
abstract class Shape{ //抽象类定义一个形状类,用abstract关键字修饰的类为抽象类
private String type; //图形形状
private String color; //图形颜色
public Shape(){
super();
} //调用的是object类的构造器
protected Shape(String type, String color){ //构造方法 protected 让子类去调用
this.type = type;
this.color = color;
}
public abstract double calcuPerimeter(); //被abstract修饰的方法只能有方法名,方法名由子类实现。
public abstract double calcuArea();
public String getType(){ //可以有方法体的实现
return this.type;
}
public String getColor(){
return this.color;
}
//计算传入数组中所有的图形的面积
public double fun(Shape[] shapes){
double result = 0;
for(Shape s: shapes){
result += s.calcuArea();
}
return result;
}
}
//我们在定义一个矩形去实现我们的抽象类,
class Retangle extends Shape{ //用普通类或者另一个抽象类去继承抽象类 但一定要实现方法体
private double length;
private double width;
public Retangle(String color, String type, double length, double width){ //构造器
super(type, color); //调用父类有参构造器
this.length = length;
this.width = width;
}
@Override
public double calcuPerimeter() {
return 2 * (length + width);
} //对父类的方法进行重写
@Override
public double calcuArea() {
return length * width;
}
}
//我们再定义一个圆形
class Circle extends Shape{
private double radius;
public Circle(String type, String color, double radius) {
super(type, color);
this.radius = radius;
}
@Override
public double calcuPerimeter(){
return 2 * Math.PI * radius;
}
@Override
public double calcuArea() {
return Math.PI * Math.pow(radius, 2);
}
// 我们来测试一下
public static void main(String[] args) {
//由于抽象类无法被实例化,所以我们需要用到向上转型,声明父类,但用子类去示例化
Shape s = new Retangle("white", "rectangle", 18, 10);
System.out.println(s.calcuArea());//计算一下当前矩形的面积
//我们来计算一下所有的形状的面积,思路:先把他们存放在数组中,然后调用用fun方法
Shape[] sArr = new Shape[4];//可以存放Shape对象的数组,也就是说,虽然抽象类无法被示例化,但是却可以当作一个数据类型来使用
sArr[0] = new Retangle("white", "rectangle", 18, 10);
sArr[1] = new Circle("black", "circle", 3.5);
sArr[2] = new Retangle("white", "rectangle", 18, 10);
sArr[3] = new Circle("black", "circle", 3.5);
System.out.println(s.fun(sArr));//s.fun(sArr)就是因为前面我们所说的无法示例化抽象类,如果要调用父类的方法,必须使用向上转型
}
结果:
接口与抽象类有什么不同
表面上(直观上):
1.含有抽象方法(abstract修饰的方法)的类叫做抽象类,而用interface关键字+ interfacename(接口名)定义的是一个接口。
2.抽象类可以有构造函数,而接口没有构造函数(也就无法实例化接口,所以无法用 new 关键字)
3.抽象类的方法如果不写限定修饰符,那么就是默认访问权限,而接口如果不写限定修饰符,所有的方法及成员都是 public static fianl修饰
4.抽象类可以有普通的成员方法,而JDK1.8之后,接口可以有普通方法,但普通方法必须用default关键字修饰
使用上:
1.对于抽象类,我们必须先继承抽象类,再实现所有的抽象方法(不然再定义抽象类),而接口是常规类去实现(implements),并且实现接口中所有的方法。
2.抽象类的子类如果没有实现完抽象类种所有的方法,那么此类必须也定义为抽象类,存在多重继承,接口可以相互实现。
(自己理解)
抽象类可以理解为 “绝对有” ,而接口可以理解为 “可以有”。
例如:门,门绝对有的功能是开门和关门。这两个方法我们就可以抽象化。
而密码门特有的功能是使用密码开门,而这个密码开门就可以理解为可以有。
那么就是门,绝对的方法:开门关门。密码门,不仅有开门关门,还有使用密码开门。那么密码门就可以去实现密码开门这个接口。而普通门不可以,因为如果实现了密码开锁,那么就不再是普通门,而是密码门。