抽象类与接口


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));

如果一个类实现了多个接口,那么这种类型的对象就可以被赋值给任一接口类型的变量。p1p2可以调用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 versions1. Constant variables
2.Abstract methods
jdk81. Constant variables
2.Abstract methods
3.Default methods
4.Static methods
jdk91. 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抽象类

对于需要实现接口的具体类而言,有两个选择:一个是实现接口,自己实现全部方法;另一个则是继承抽象类,然后根据需要重写方法。

继承的好处是复用代码,只重写需要的部分即可,需要编写的代码比较少,容易实现。不过,如果这个具体类已经有父类了,那就只能选择实现接口了。

抽象类相对于具体类,它用于表达抽象概念,虽然从语法上抽象类不是必需的,但它能使程序更为清晰,可以减少误用。抽象类和接口经常相互配合,接口定义能力,而抽象类提供默认实现,方便子类实现接口。

Reference

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xylitolz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值