详解 接口
在本篇博文的内容之前,本人要提醒一点,这个知识点,虽然可能会在现在看起来不是很有用,但是本人能够打包票的说,这篇博文的知识点,和class同等重要,那么,开始我们这篇博文内容的讲解吧!
我们的每一个程序都有一个关键字——class.
那么,在本篇博文中,本人要讲一个和class同等级的关键字——interface
我们知道:以class开头的文件是 类,而以interface开头的文件,就是接口
但是接口却有如下特点:
接口的特点:
- 接口用关键字interface表示 格式: interface 接口名 {}
- 类实现接口用implements表示 格式: class 类名 implements 接口名 {}
- 接口不能实例化
问:那么,接口如何实例化呢?
答曰:按照多态的方式来实例化。- 接口的子类
a:可以是抽象类。但是意义不大。
b:可以是具体类。要重写接口中的所有抽象方法。(推荐方案)- 和class平起平坐
- 只含有
抽象方法;
确定了的 方法——本人先根据我们学习C的函数来讲:相当于规定了函数的名称、参数、函数类型、函数功能(只管有什么功能,不管如何实现);- 任何接口的实现类,都可以看成该接口的派生类。若派生类没有完成“所有”的接口中的>抽象方法,则认为该派生类也是抽象类;
- 接口也可以继承接口,但是必须要在子接口中用default定义父接口的所有方法
接口的成员具有如下特点:
接口成员特点:
- 成员变量:只能是常量,并且是静态的。
默认修饰符:public static final- 构造方法:接口没有构造方法。
- 成员方法:只能是抽象方法。
默认修饰符:public abstract
现在,本人来介绍一下 类 和 接口 之间的关系:
类与类,类与接口,接口与接口的关系:
- 类与类:
继承关系,只能单继承,可以多层继承。- 类与接口:
实现关系,可以单实现,也可以多实现。
并且还可以在继承一个类的同时实现多个接口。- 接口与接口:
继承关系,可以单继承,也可以多继承。
下面,我们来编写一个接口,顺便来展示下如何继承接口:
IShape .java:
package com.mec.shape;
public interface IShape {
//本人对于接口中default修饰的方法认识:
//默认派生类中用到此抽象方法的“大多数”都是按照这种实现方法
//至于剩余少数,则可以按照在派生类中覆盖这个方法来实现其目的
default double rounder() {
return 1.0;
}
double area();
}
上面的代码,就表示我定义了一个接口,那么,下面我来用一个类来继承这个接口:
Rectangel类;
package com.mec.shape;
public class Rectangel implements IShape { //继承哪个接口,就要在该类名后写上:implements 接口名。若是继承多个接口,只需在每个接口之间
private double width;
private double height;
public Rectangel() {
}
public Rectangel(double width, double height) {
this.height = height;
this.width = width;
}
//继承接口,就要将其内部所有的方法实现(除default修饰的方法外)
@Override
public double rounder() {
return 2 * (width + height);
}
@Override
public double area() {
return width * height;
}
}
下面,本人再编写一个类,来观看下运行结果:
Test类:
package com.mec.shape;
public class Test {
public static void main(String[] args) {
IShape rectangel = new Rectangel(3.5, 6.5);
System.out.println("周长:" + rectangel.rounder()+ " 面积:" + rectangel.area());
IShape circle = new IShape() {
private double radius;
public IShape setRadius(double radius) {
this.radius = radius;
return this;
}
@Override
public double rounder() {
return 2 * Math.PI * radius;
}
@Override
public double area() {
return Math.PI * radius *radius;
}
}.setRadius(2.0);
System.out.println("周长:" + circle.rounder()+ " 面积:" + circle.area());
//若这里输出true,则表明派生类是接口的子类
System.out.println(circle instanceof IShape);
}
}
我们来观看下运行结果:
上图说明一个问题:
接口的实现类 的对象,就是 接口 的对象
下面,本人来讲述下 接口 与 HashMap 的联合运用:
IMyUnionType.java:
package com.mec.shape;
public interface IMyUnionType { //接口的名称必须以大写字母“I”开头
}
在这个类中,我们什么先都不写,然后在我们之前的 Complex类、OtherPoint类中,都让其继承这个接口:
Complex类;
package com.mec.study.complex;
import com.mec.shape.IMyUnionType;
public class Complex implements IMyUnionType {
private double real;
private double vir;
public Complex(double real, double vir) {
this.real = real;
this.vir = vir;
}
public Complex() {
this(0.0, 0.0);
}
public Complex(Complex c) {
this(c.real, c.vir);
}
public double getReal() {
return real;
}
public void setReal(double real) {
this.real = real;
}
public double getVir() {
return vir;
}
public void setVir(double vir) {
this.vir = vir;
}
public Complex add(Complex c) {
this.real += c.real;
this.vir += c.vir;
return this;
}
public static Complex add(Complex one, Complex another) {
return new Complex (one).add(another);
}
private static Complex opposite(Complex c) {
return new Complex(-c.real, -c.vir);
}
private static Complex reciprocal(Complex c) {
double model = c.real * c.real + c.vir * c.vir;
if(Math.abs(model) < 1e-6) {
return null;
}
return new Complex(c.real / model, -c.vir / model);
}
public Complex sub(Complex c) {
return this.add(opposite(c));
}
public static Complex sub(Complex one, Complex another) {
return new Complex(one).add(opposite(another));
}
public Complex mul(Complex one) {
double real = this.real;
this.real = real * one.real - this.vir * one.vir;
this.vir = real * one.vir - this.vir * one.real;
return this;
}
public static Complex mul(Complex one, Complex another) {
return new Complex (one).mul(another);
}
public static Complex div(Complex one, Complex another) {
Complex rec = reciprocal(another);
return rec == null ? null : new Complex(one).mul(rec);
}
@Override
public String toString() {
return "(" + real + "," + vir + ")";
}
@Override
public boolean equals(Object obj) {
if(null == obj) {
return false;
}
if(this == obj) {
return true;
}
if(!(obj instanceof Complex)) {
return false;
}
Complex c = (Complex) obj;
return Math.abs(this.real - c.real) < 1e-6
&& Math.abs(this.vir - c.vir) < 1e-6;
}
}
OtherPoint类:
package com.mec.about_point;
import com.mec.shape.IMyUnionType;
public class OtherPoint extends Point implements IMyUnionType {
public OtherPoint() {
super();
}
public OtherPoint(int row, int col) {
super(row, col);
}
}
然后,编写一个 Demo类,来用HashMap来存储这些类的对象:
Demo类:
package com.mec.about_test;
import java.util.HashMap;
import java.util.Map;
import com.mec.study.complex.Complex;
import com.mec.shape.IMyUnionType;
import com.mec.about_point.OtherPoint;
public class Demo {
public static void main(String[] args) {
//这里是我们用名为objectMap的HashMap来存储 两个类的对象
Map<String, IMyUnionType> objectMap = new HashMap<>();
OtherPoint p =new OtherPoint(1, 2);
if(p instanceof IMyUnionType) {
IMyUnionType q = (IMyUnionType) p;
objectMap.put("点", q);
}
Complex c = new Complex();
objectMap.put("复数", c);
}
}
下面,我们来看一下运行结果:
运行结果没有出错,这就表明,我们未来可以用这种手段来保护我们所编写的一些类,只给外部提供那张表即可。
这里对default关键字 做一下解释:
default 在 接口 中的的应用:
一般用于接口中有默认实现手段;
但若想在派生类中自行完成,可以覆盖基类中的default方法。
最后,本人还要讲解一点:
可能有同学想问:本人说过一个类只能有一个基类,但一个类可以有多个接口。
那么,若是两个接口中有同名的成员 或者 同名的方法 呢?
答曰:若是一个类有两个以上的接口时,调用该接口的成员或方法时,一般都会加上如下的前缀,以表明是哪个接口的成员或方法:
接口名.
在文章的末尾,本人来介绍一个有关接口的最最最最最重要的知识点
那就是——接口的四大性质:
接口的 性质:
- 消费未来;
- 海纳百川;
- 开闭原则;
- 分类。
而这四大性质,本人不进行深入讲解,先提出,当在本人之后的博文中遇到时,本人再来重新进行实例化讲解。
因为现在进行深入讲解的话,同学们可能会因为没有见过应用场合而觉得其作用很鸡肋。
但当我们之后的博文中出现了遇到了这四大基本作用时,本人将通过例子来让同学们了解其的重要性。