前言
介绍Java抽象类和接口的概念,使用以及区别。
目录
一、抽象类
1.概念简述
像类是对象的抽象一样,抽象类就是类的进一步抽象。我对此的理解是:就好比水果,它是对苹果、梨子、桃子等具体对象的抽象,而植物就属于对水果的进一步抽象,可以看成是抽象类。同理,抽象类还可以再进一步被抽象为更高一级的抽象类。
抽象类的主要作用是用来继承的,因此,它不能实例化。但继承它的具体类可以实例化。
2.格式
[修饰符列表] abstract class 类名{
类体;
}
由于抽象类的作用主要是继承,很明显,abstract和final就是一对相冲突的关键字,就不能联合使用 。
public abstract class AbstractTest {
}
3.抽象方法
抽象类和具体类除了含义和格式上有区别外,另一个重要区别是,抽象类可以包含抽象方法,而具体类不行。换句话说,就是抽象方法只能出现在抽象类中,而抽象类可以包含抽象方法也可以不包含。
抽象方法是指没有实体的方法,它没有方法体,直接在括号后加一个分号。
抽象方法的格式是:
[修饰符列表] abstract 返回值类型 方法名(形式参数列表);
public abstract class AbstractTest {
int version;
//抽象类中也可以有构造方法
public AbstractTest() {
}
public AbstractTest(int version) {
this.version = version;
}
//抽象方法只能出现在抽象类中
//抽象方法没有方法体!!!
public abstract void fun();
//也可以有非抽象方法
public void doSome(){
System.out.println("我是非抽象方法");
}
}
抽象类中可以有构造方法,也可以有抽象方法和非抽象方法。
4.具体类继承抽象类
与普通具体类之间的继承格式一样,具体类去继承抽象类也是用的extends关键字。但是注意,当被继承的抽象类中有抽象方法时,去继承的具体类一定要全部覆盖它的抽象方法,并同时去掉abstract关键字。
public abstract class AbstractTest {
int version;
//抽象类中也可以有构造方法
public AbstractTest() {
}
public AbstractTest(int version) {
this.version = version;
}
//抽象方法只能出现在抽象类中
//抽象方法没有方法体!!!
public abstract void fun1();
public abstract void fun2();
//也可以有非抽象方法
public void doSome(){
System.out.println("我是非抽象方法");
}
}
class Test extends AbstractTest{
String name;
//具体类去继承抽象类时要覆盖它的全部抽象方法,并同时去掉abstract关键字
public void fun1(){
System.out.println("我是覆盖的第一个抽象方法");
}
public void fun2(){
System.out.println("我是覆盖的第二个抽象方法");
}
}
这里补充一下,除抽象类之间的相互继承和具体类去继承抽象类外,抽象类也是可以继承非抽象类,也就是具体类的。
二、接口
1.概念简述
接口通俗点来说就是将两个对象连接的桥梁,约定了双方来往的通道。比如说我们网上购物时,一般不是直接向商家订购付款。而是会先浏览商家展示出来的商品图片和相关信息介绍的页面,然后在该页面下单付款。这个商品展示页就可以看成是顾客和商家之间交易的一个接口。它规定商品介绍要图文并茂,还要有确认下单选择。
2.格式和内容
接口的格式:
[修饰符列表] interface 接口名{
}
接口编译后同样生成字节码文件。
接口中在JDK7及以前只能包括常量(public static final修饰的变量)和抽象方法,JDK8以后还能包含默认和静态方法,到JDK9时又增添了私有方法。由于一般出现的都是常量和抽象方法,因此常量的public static final可以省略,抽象方法的public abstract也可以省略。
接口与抽象类的主要区别就在内容包含上。可以看出,接口是全抽象的,而抽象类则算是半抽象。
public interface InterfaceTest {
//接口中JDK7及以前只能包括常量和抽象方法
public static final String page = "购物页面";
//常量的public static final可省略
int num = 1;
//抽象方法的public abstract也可省略
void show();
}
3.接口的继承和实现
接口与接口之间可以用extends实现继承,并且接口支持多继承。继承的多个接口之间用逗号隔开。
interface A{
}
interface B{
}
interface C extends A,B{
}
具体类和抽象类去继承接口都叫做实现,关键字是implements 。
class Merchant implements InterfaceTest,A{
//实现方法时记得要在方法前加上被省略的public
public void show(){
System.out.println("这是商品展示页面");
}
public void afun(){
System.out.println("多实现时要覆盖所有接口的所有方法");
}
}
实现接口时也要实现所有的抽象方法,记得在方法的返回类型前加上被省略的public。
Java支持多实现,实现的接口之间用逗号隔开,该具体类要实现所有接口的所有抽象方法。
4.接口实现多态
与基类型引用指向派生类对象一样,接口也可以充当这个基类,凡是实现了该接口的具体类在创建对象时都可以用该接口类型的变量去接收,从而更好实现多态。
public class Test01 {
public static void main(String[] args) {
//接口也可以实现多态
InterfaceTest t = new Merchant();
//但是接口向下转型时由于多实现的存在,Java编译阶段并不会判断
// 转换成的类型和被转换的变量的接口类型是否有实现关系,运行时才能发现错误。
B b =(B) t;//Merchant类并没有实现B这个接口,但是编译器并不会判错
}
}
但是接口在向下转型时Java编译阶段并不会判断转换成的类型和被转换的变量的接口类型是否有实现关系,运行时才能发现错误。
5.extends和implements
extends和implements可以同时出现,格式是extends在前,implements在后:
class 类名 extends 基类 implements 接口{
类体
}
class Test02 extends Merchant implements InterfaceTest{
}
就算没有写出继承任何类,在实现接口时也会默认继承Object类。
三、接口简单使用实践
在接口的定义和使用过程中,最先要搞清楚的是哪部分内容是接口,以及谁是调用者和谁是实现者。
代码:
/**
* 测试程序
*/
class Test001{
public static void main(String[] args) {
//创建各个商家
BookMerchant com1 = new BookMerchant("高数A1",21,200);
PenMerchant com2 = new PenMerchant("中国",3,500);
//创建顾客,并传入商家类购买商品
Customer c = new Customer("小李",com1);
c.buy(50,2);
System.out.println("------------------------------");
//买另外的东西
c.setSp(com2);
c.buy(10,3);
}
}
/**
* 购物页面窗口
*/
interface ShoppingPage {
public static final String page = "购物页面";
/**
* 商品展示
*/
void show();
/**
* 交易提示
* @param n 购买商品的数量
*/
void buy(int n);
}
/**
* 书籍商家类,接口的实现者
*/
class BookMerchant implements ShoppingPage{
private String name;
private int price;
private int number;
public BookMerchant() {
}
public BookMerchant(String name, int price, int number) {
this.name = name;
this.price = price;
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public void show(){
System.out.println("这是该书《"+this.name+"》的商品展示页面");
System.out.println("价格为:"+this.price+",库存为:"+this.number);
}
public void buy(int number){
if(number <= this.number){
System.out.println("您购买的"+number+"件《"+this.name+"》商品购买成功");
this.number -= number;
}
else{
System.out.println("抱歉,商品库存不够,还剩"+this.number+"件,请重新选择");
}
}
}
/**
* 笔商家类
*/
class PenMerchant implements ShoppingPage{
//笔的生产地
private String nationality;
private int price;
private int number;
public PenMerchant() {
}
public PenMerchant(String nationality, int price, int number) {
this.nationality = nationality;
this.price = price;
this.number = number;
}
public String getNationality() {
return nationality;
}
public void setNationality(String nationality) {
this.nationality = nationality;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public void show(){
System.out.println("这是来自"+this.nationality+"的笔的商品展示页面");
System.out.println("价格为:"+this.price+",库存为:"+this.number);
}
public void buy(int number){
if(number <= this.number){
System.out.println("您购买的"+number+"件商品购买成功");
this.number -= number;
}
else{
System.out.println("抱歉,商品库存不够,还剩"+this.number+"件,请重新选择");
}
}
}
/**
* 顾客类,接口的使用者
*/
class Customer{
private String name;
private ShoppingPage sp;
public Customer() {
}
public Customer(String name, ShoppingPage sp) {
this.name = name;
this.sp = sp;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ShoppingPage getSp() {
return sp;
}
public void setSp(ShoppingPage sp) {
this.sp = sp;
}
/**
* 顾客购物
* @param money 顾客的预期价格
* @param number 顾客想要的商品数量
*/
public void buy(int money,int number){
sp.show();
if(sp instanceof BookMerchant){
BookMerchant bm = (BookMerchant) sp;
if(bm.getPrice()*number > money){
System.out.println("不买了");
}
else{
bm.buy(number);
}
}
if(sp instanceof PenMerchant){
PenMerchant pm = (PenMerchant) sp;
if(pm.getPrice()*number > money){
System.out.println("不买了");
}
else{
pm.buy(number);
}
}
}
}
在该例子中,很明显,商品的展示页面应该是顾客和商家之间的桥梁,应定义为接口。展示页面应该包括商品的相关介绍以及购买服务。商家应该是该页面的实现者,而顾客则应该是使用者。
贴上运行截图:
接口的使用使编程由面向具体编程到面向抽象编程,再到面向接口编程。它极大的降低了程序的耦合度,提高了程序的扩展性。
如有错误或不妥之处,希望能得到批评指正,将不胜感激。