文章目录
1. 接口
1.1 定义
public interface iMyComparable {
int compareTo(Object other);
}
- Java使用
interface
这个关键字来声明接口,修饰符一般都是public
- 关键字
interface
后面就是接口的名字iMyComparable - 接口定义里面,声明了一个方法compareTo,但没有定义方法体,Java8之前接口内不能实现方法。接口方法不需要加修饰符,加与不加都是public abstract,即都是抽象方法
1.2 使用接口
public class Point implements iMyComparable {
private int x;
private int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public double distance(){
return Math.sqrt(x*x+y*y);
}
@Override
public int compareTo(Object other) {
if(!(other instanceof Point)){
throw new IllegalArgumentException();
}
Point otherPoint = (Point)other;
double delta = distance() - otherPoint.distance();
if(delta<0){
return -1;
}else if(delta>0){
return 1;
}else{
return 0;
}
}
}
与类不同,接口不能new,不能直接创建一个接口对象,对象只能通过类来创建。但可以声明接口类型的变量,引用实现了接口的类对象,例如:
iMyComparable p1 = new Point(2,3);
iMyComparable p2 = new Point(1,2);
System.out.println(p1.compareTo(p2));
如果一个类实现了多个接口,那么这种类型的对象就可以被赋值给任一接口类型的变量。p1
和p2
可以调用iMyComparable
接口的方法,也只能调用iMyComparable
接口的方法,实际执行时,执行的是具体实现类的代码。
1.3 接口的本质
将类看作一种自定义的数据类型,在一些情况下,并不能反应对象以及对对象操作的本质。很多时候,我们实际上关心的,并不是对象的类型,而是对象的能力,只要能提供这个能力,类型并不重要。
类型并不重要,重要的是能力。类可以实现接口,表示类的对象具有接口所表示的能力。一个类可以实现多个接口,表明类的对象具备多种能力。
针对接口编程而非具体类型进行编程,是计算机程序的一种重要思维方式。
接口的优点如下:
- 代码复用,同一套代码可以处理多种不同类型的对象
- 降低了耦合,提高了灵活性。使用接口的代码依赖的是接口本身,而非实现接口的具体类型,程序可以根据情况替换接口的实现,而不影响接口使用者
1.4 接口的细节
1.4.1 接口中的变量
// 接口中可以定义变量
public interface iMyComparable {
public static final int a = 0;
int compareTo(Object other);
}
定义了一个变量int a
,修饰符public static final
是可选的,即使不写也是public static final
,可以通过接口名.变量名
的方式使用,如iMyComparable.a
1.4.2 接口的继承
public interface iBase1 {
void method();
}
public interface iBase2 {
void method();
}
public interface iChild extends iBase1,iBase2 {
}
一个接口可以继承其他接口,继承的基本概念与类一样,但与类不同的是,接口可以有多个父接口,接口的继承同样使用extends
关键字,多个父接口之间以逗号分隔。
1.4.3 类的继承与接口
public class Child extends Father implements iFather {
// 代码主体
}
类的继承与接口可以共存,类可以在继承基类的情况下,同时实现一个或多个接口。关键字extends
要放在implements
之前。
1.4.4 instanceof
Child child = new Child();
if (child instanceof iFather) {
}
与类一样,接口也可以使用instanceof
关键字,用来判断一个对象是否实现了接口。
1.5 Java8和Java9对接口的增强
1.5.1 Java8
在Java8之前,接口中的方法都是抽象方法,都没有实现体,Java8允许在接口中定义两类新方法:静态方法和默认方法,它们都有实现体:
public interface IDemo {
int a = 0;
void method();
public static void test1() {
System.out.println("Java8对接口增强-静态方法");
}
default void test2() {
System.out.println("Java8对接口增强-默认方法");
}
}
-
test1()
就是一个静态方法,可以通过IDemo.test1()
调用。实现类和实现是不可以调用的。 -
test2()
是一个默认方法,用关键字default
表示。默认方法与抽象方法都是接口的方法,不同在于,默认方法都有默认的实现,实现类可以改变它的实现,也可以不改变。引入默认方法主要是函数式数据处理的需求,是为了便于给接口增加功能 -
在没有默认方法之前,Java很难给接口增加功能,比如List接口,因为有太多非Java JDK控制的代码实现了该接口,如果给接口增加一个方法,则那些接口的实现就无法在新版Java上运行,必须改写代码,实现新的方法,这显然是无法接受的。函数式数据处理需要给一些接口增加一些新的方法,所以就有了默认方法的概念,接口增加了新方法,而接口现有的实现类也不需要必须实现。
1.5.2 Java9
public interface IDemoPrivate {
private void common() {
System.out.println("common");
}
default void actionA() {
common();
}
default void actionB() {
common();
}
}
在Java8中,静态方法和默认方法都必须是public的,Java9去除了这个限制,它们都可以是private的,引入private方法主要是为了方便多个静态或默认方法复用代码。
1.5.3 总结:Java7-Java9中接口概念的变化
Interface | |
---|---|
jdk7 or earlier versions | 1. Constant variables 2.Abstract methods |
jdk8 | 1. Constant variables 2.Abstract methods 3.Default methods 4.Static methods |
jdk9 | 1. Constant variables 2.Abstract methods 3.Default methods 4.Static methods 5.Private methods 6.Private Static methods |
Java7-Java9中接口概念的变化:
- 在 jdk 7 或更早版本中,接口里面只能有常量变量和抽象方法。这些接口方法必须由选择实现接口的类实现
- jdk 8 的时候接口可以有默认方法和静态方法功能
- Jdk 9 在接口中引入了私有方法和私有静态方法
2. 抽象类
顾名思义,抽象类就是抽象的类。抽象是相对于具体而言的,一般而言,具体类有直接对应的对象,而抽象类没有,它表达的是抽象的概念,一般是具体类的比较上层的父类。比如,狗是具体对象,而动物则是抽象概念;正方形是具体对象,而图形则是抽象概念。
2.1 抽象方法和抽象类
-
只有子类才知道如何实现的方法,一般被定义为抽象方法。
-
抽象方法是相对于具体方法而言的,具体方法有实现代码,而抽象方法只有声明没有实现。接口中的方法(非Java8引入的静态和默认方法)都是抽象方法。
-
抽象方法与抽象类都使用
abstract
这个关键字来声明-
public abstract class Shape{ // ... public abstract void draw(); }
-
定义了抽象方法的类必须被声明抽象类,不过,抽象类可以没有抽象方法。
-
抽象类和具体类一样,可以定义具体方法、实例变量等,它和具体类的核心区别是:抽象类不能创建对象(比如,不能使用
new Shape()
),而具体类可以。 -
一个类在继承抽象类后,必须实现抽象类中定义的所有抽象方法,除非它自己也声明为抽象类。
-
public class Circle extends Shape { // ... @Overiride public void draw() { // ... } }
-
与接口类似,抽象类虽然不能使用
new
创建对象,但可以声明抽象类的变量,引用抽象类具体子类的对象 -
Shape shape = new Circle(); shape.draw;
-
2.2 为什么需要抽象类
引入抽象类和抽象方法是Java提供的一种语法工具,对于一些类和方法,引导使用者正确的使用它们,减少误用:
- 使用抽象类,类的使用者创建对象的时候,就知道必须要使用某个具体子类,而不可能误用不完整的父类
- 使用抽象方法而非空方法体,子类就知道它必须要实现该方法,而不可能忽略,若忽略,Java编译器会提示错误。
3. 抽象类与接口的区别与联系
抽象类与接口对比 | |
---|---|
相似之处 | 1. 都不能用于创建对象 可以声明接口类型的变量,引用实现了接口的类对象 可以声明抽象类的变量,引用抽象类具体子类的对象 2.接口中的方法(非Java8引入的静态和默认方法)都是抽象方法,如果抽象类中只定义了抽象方法,那抽象类和接口就更像了 |
不同之处 | 1. 接口中不能定义实例变量,而抽象类可以 2.一个类可以实现多个接口,但只能继承一个类 3.从设计层面来说,抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为的规范 |
抽象类和接口是配合而非替代关系,它们经常一起使用,接口声明能力,抽象类提供默认实现,实现全部或部分方法,一个接口经常有一个对象的抽象类。比如,在Java类库中,有:
- Collection接口和对应的AbstractCollection抽象类
- List接口和对应的AbstractList抽象类
- Map接口和对应的AbstractMap抽象类
对于需要实现接口的具体类而言,有两个选择:一个是实现接口,自己实现全部方法;另一个则是继承抽象类,然后根据需要重写方法。
继承的好处是复用代码,只重写需要的部分即可,需要编写的代码比较少,容易实现。不过,如果这个具体类已经有父类了,那就只能选择实现接口了。
抽象类相对于具体类,它用于表达抽象概念,虽然从语法上抽象类不是必需的,但它能使程序更为清晰,可以减少误用。抽象类和接口经常相互配合,接口定义能力,而抽象类提供默认实现,方便子类实现接口。