温故而知新——java抽象类和接口

来源:互联网 发布:无经验淘宝客服简历 编辑:程序博客网 时间:2024/06/02 21:46

抽象类

  一般我们编写一个类时,常常会为该类定义一些方法,这些方法都有具体的实现。但是在某些情况下,父类只知道子类应该包含什么方法,但是不知道子类是怎么实现这个方法的。比如几何图形类包含三角形子类,长方形子类,圆形子类,父类知道这些子类要有计算周长和面积的方法,但是却不知道各自怎么实现的(各自实现方法也是不同的)。
  如何既能让父类定义计算周长和面积的方法,又不用提供具体的方法实现呢?
  使用抽象方法即可满足该要求:抽象方法只有方法的声明,没有方法的具体实现。

抽象方法和抽象类

  抽象方法和抽象类必须使用 abstract 修饰符来定义,有抽象方法的类只能被定义成抽象类,抽象类里可以没有抽象方法。
  
  抽象方法和抽象类的规则如下。
  
  ①抽象类必须使用 abstract 修饰符来修饰,抽象方法也必须使用 abstract 修饰符来修饰,抽象方法不能有方法体。 
  
  ②抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。即使抽象类里不包含抽象方法,这个抽象类也不能创建实例。 
  
  ③抽象类可以包含成员变量、方法〈普通方法和抽象方法都可以)、构造器、初始化块、内部类(接口、枚举)5中成分。抽象类的构造器不能用来创建实例,主要用来被其他子类调用。
  
  ④抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
  
  ⑤如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。

  抽象类可以用“有得有失”来形容:
  得:抽象类可以包含抽象方法;
  失:抽象类不能创建实例。
  
  定义抽象类的方法:
  在普通类上增加 abstract 修饰符即可。
  
  定义抽象方法:
  在普通方法上增加 abstract 修饰符,并把普通方法大括号中的方法体部分全部删掉,并在方法后增加分号。

  通过代码来演示抽象类和抽象方法:
  

abstract class Shape{//抽象图形类        public abstract double getArea();//抽象方法,计算面积        public abstract double getPan();//计算周长}
class Square extends Shape{ //定义一个正方形类,继承图形抽象类        protected double len;        Square(double len){                this.len = len;        }        public double getArea(){//抽象方法的具体实现                return len*len;        }        public double getPan(){//抽象方法的具体实现                return 4*len;        }}
class Rectangle extends Square{//定义一个长方形类,继承图形抽象类        private double wid;        Rectangle(double len,double wid){                super(len);                this.wid = wid;        }        public double getArea(){//抽象方法的具体实现                return wid*len;        }        public double getPan(){//抽象方法的具体实现                return (wid+len)*2;        }}
class Circle extends Shape{//定义一个圆形类,继承图形抽象类        private double r;        Circle (double r){                this.r = r;        }        public double getArea(){//抽象方法的具体实现                return Math.PI*r*r;        }        public double getPan(){//抽象方法的具体实现                return Math.PI*r*2;        }}

  从这里可以看出,抽象类就是为了继承而存在的,如果你定义了一个抽象类,却不去继承它,那么等于白白创建了这个抽象类,因为你不能用它来做任何事情。对于一个父类,如果它的某个方法在父类中实现出来没有任何意义,必须根据子类的实际需求来进行不同的实现,那么就可以将这个方法声明为abstract方法,此时这个类也就成为abstract类了。

接口

  在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类。这两者有太多相似的地方,又有太多不同的地方。

  抽象类是从多个类中抽象出来的模板,如果将这种抽象进行得更彻底,则可以提取出一种更加特殊的“抽象类”——接口。
  接口里不能包含普通方法(抽象类可以),接口里所有的方法都是抽象方法。
  
  接口定义了某一些类所需要遵守的规范,接口不关心这些类的内部状态,也不关心这些类里方法的具体实现细节,它只规定类里必须提供的方法。
  接口不提供任何实现,接口体现的是规范和实现分离的哲学

接口和抽象类语法上的区别

  ①抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法。
  ②抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的。
  ③接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法。
  ④一个类只能继承一个抽象类,而一个类却可以实现多个接口。(单继承多实现)。

抽象类和接口的例子

  下面看一个网上流传最广泛的例子:
  门和警报的例子:门都有open( )和close( )两个动作,此时我们可以通过抽象类和接口来定义这个抽象概念。
  

abstract class Door {//抽象类    public abstract void open();    public abstract void close();}
interface Door {//接口    public abstract void open();    public abstract void close();}

  现在如果我们需要门具有报警alarm( )的功能,那么该如何实现?下面提供两种思路:
  ①将这三个功能都放在抽象类里面,但是这样一来所有继承于这个抽象类的子类都具备了报警功能,但是有的门并不一定具备报警功能。
  ②将这三个功能都放在接口里面,需要用到报警功能的类就必须实现这个接口中的所有抽象方法,包括open( )和close( ),但是很可能这个类根本就不具备open( )和close( )这两个功能,比如火灾报警器。
  
  从这里可以看出, Door的open() 、close()和alarm()根本就属于两个不同范畴内的行为,open()和close()属于门本身固有的行为特性,而alarm()属于延伸的附加行为。
  因此最好的解决办法是单独将报警设计为一个接口,包含alarm()行为,Door设计为单独的一个抽象类,包含open和close两种行为。再设计一个报警门继承Door类和实现Alarm接口。
  

interface Alram {//单独定义一个警报接口,谁需要谁实现它    void alarm();//接口中方法和属性的修饰符都是可以省略的,为防止写错,直接不写就行}abstract class Door {//定义门的抽象类    void open();//这里没有abstract,是抽象类中的普通方法    void close();}class AlarmDoor extends Door implements Alarm {    void oepn() {      //....    }    void close() {      //....    }    void alarm() {      //....    }}
0 0
原创粉丝点击