浅谈JAVA抽象类及接口
作为面向对象语言,JAVA同样具有封装、继承和多态的基本特征,其中抽象类和接口很好地体现了这一点,因为结构相似但又有实际的不同,所以这里放在一起说。
假如我们要写一个Zoo的project,有多种动物的类Dog, Cat, Parrot等,它们都有eat()的方法,我们会自然想到建造一个Animal的类作为父类存放这些动物共有的方法及属性,如下:
public class Animal {
public void eat(String food) {
System.out.println("I am eating " + food);
}
}
public class Dog extends Animal {
}
----------------------------------------------------
应用时:
Animal Snoopy=new Dog();
Snoopy.eat("Cookies");
我们发现即使不用抽象类也可以很好地完成任务,那么为什么要用抽象类而不用普通类呢?
先从抽象方法讲起:
抽象方法
抽象方法指用“abstract” 修饰的方法,该方法只有声明,没有实现的方法体,它的具体实现交给子类来确定,可以看出抽象方法是生而为“继承”的,例如在Animal中只指定eat()方法,具体怎么吃让小狗小猫去决定:
abstract void eat(String food);
使用抽象方法有三点要求:
- 如果一个类包含抽象方法,那么该类必须是抽象类。
- 任何子类必须重写父类的抽象方法,或者声明自身为抽象类。
- 构造方法及静态方法(类方法,用static修饰)不能声明为抽象方法。
那么问题的答案很明了了,当Animal中有抽象方法时,那么使用普通类就不行了,必须使用抽象类,那么类里没有抽象方法,可不可以声明为抽象类呢?有何作用?
抽象类
抽象类是对对象(类)的抽象,和抽象方法一样,声明抽象类时只需要使用修饰符“abstract” 就可以:
public abstract class Animal {
abstract void eat(String food);
}
抽象方法必须包含在抽象类里,但抽象类里不一定要有抽象方法
先回答前一个小问题,没有抽象方法,类一样可以声明为抽象类,和普通类除了修饰符其余写法一样
抽象类只能被继承,不可以实例化
很好理解,抽象类作为抽象出来的“模具”存在,自然不能“实例化”,只有抽象类的非抽象子类可以创建对象。第二个小问题答案也就有了,没有抽象方法的抽象类的作用是:强制子类去继承该类,并强制不允许被实例化。基于此,人们通常在设计阶段决定要不要设计抽象类。
抽象类可以有无数子类,但一个子类只能继承一个抽象类
这个和普通类相同,子类只允许有一个父类。注意区分接口:子类可以实现多个接口。
抽象类可以继承别的抽象类,可以实现别的接口
抽象类可以有构造函数,只是是为子类提供的
抽象类内构造函数是要求子函数必须实现的,所以在子类的构造函数中必须加一句
super();
public class Dog extends Animal { public Dog() { super(); } @Override public void eat(String food) { //do something } }
我们了解到还有一种不能实例化也没有方法具体实现的机制,接口,那和抽象类有什么区别?
接口
接口是对对象行为的抽象,通常以interface来声明,是抽象方法的集合。接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。
public interface Movable {
/*public static final*/ String name = null; //这里省略public static final,因为接口里变量
//默认都是常量,而且不能private
/*public abstract*/ void walk(); //这里省略public abstract,因为接口里方法默认都是抽象的,符合
void run(); //抽象方法的一切特点
}
如上图所示,接口内只能声明public常量和抽象方法
public static final 和 public abstract 可以省略
接口内没有构造函数
因为接口不能实例化,而且接口不是类,只是一类动作的集合,所以不存在“构造”的概念
接口不是被类继承(extends)了,而是要被类实现(implements)。
准确地说,接口不是类,所以不能被继承,它是方法的集合,可以被实现。(用法相似,称呼不同)
子类可以实现多个接口
这一点是与其他类最明显的差异,普通类及抽象类都只能单一继承
接口可以继承别的接口,但不能继承类
抽象类与接口的区别
抽象类是对对象的抽象;接口是对行为的抽象
虽然两者在使用的相似,甚至可以互换而不出现bug,但两者设计的初衷是不同的
- 抽象类是一类事物,像Animal对Dog;
- 接口是一类动作,像Move对walk();
抽象类单一继承;接口可以多“继承”(准确地应该是实现 )
抽象类可以像普通类一样声明各类字段,各类方法;接口只能声明常量和抽象方法
- 抽象类可以实现包括抽象方法的其他任意方法;
- 接口只有常量和
抽象方法(在最新的JAVA8中情况有所改变,本篇只点不讲) - 接口内不能有构造函数而抽象类可以有;
基本区别就是这些,可以在日后的实践中慢慢掌握,目前来说必须掌握的是1.2.两条。