抽象类(abstract class):不能实例化的类,使用关键字abstract修饰,含有抽象方法(abstract method)。
抽象方法(abstract method):在方法头中使用关键字abstract修饰,只有函数的声明定义,没有函数体的方法。
包含抽象方法的类必须是抽象类,抽象类可以不包含抽象方法。
之前有写过一个几何、圆、矩形的类,现在改写几何类为抽象类,包括求面积、求周长这两个抽象方法:
package demo; import java.util.Date; /** * 定义一个几何抽象类 * Created by luts on 2015/11/29. */ public abstract class GeometricObject { private String name = null; //几何形状名字 private String color = "white"; private boolean filled = false; private java.util.Date dateCreated; //无参构造器 protected GeometricObject(){ dateCreated = new java.util.Date(); } //含参构造器 protected GeometricObject(String name, String color, boolean filled){ this.name = name; this.color = color; this.filled = filled; dateCreated = new java.util.Date(); } public String getName() { return name; } public void setName(String name){ this.name = name; } public String getColor(){ return color; } public void setColor(String color) { this.color = color; } public boolean isFilled() { return filled; } public void setFilled(boolean filled){ this.filled = filled; } public Date getDateCreated() { return dateCreated; } public String toString(){ return "created on " + dateCreated + "\ncolor: " + color + " and filled: " + filled ; } public abstract double getArea(); //求面积的抽象函数,在子类中实现 public abstract double getPerimeter(); //求周长的抽象函数,在子类中实现 }
1 package demo; 2 3 /** 4 * 圆类,继承于几何类 5 * Created by luts on 2015/11/29. 6 */ 7 8 public class Circle extends GeometricObject { 9 private double radius; 10 11 public Circle(){ 12 13 } 14 15 public Circle(String name, double newRadius){ 16 this.setName(name); 17 this.radius = newRadius; 18 } 19 20 public Circle(double newRadius, String newColor, boolean newFilled){ 21 this.radius = newRadius; 22 setColor(newColor); 23 setFilled(newFilled); 24 } 25 26 public double getRadius(){ 27 return radius; 28 } 29 30 public double getArea(){ 31 return radius * radius * Math.PI; 32 } 33 34 public double getDiameter(){ 35 return 2 * radius; 36 } 37 38 public double getPerimeter(){ 39 return 2* radius * Math.PI; 40 } 41 42 public void printCircle(){ 43 System.out.println("The circle is creadted " + getDateCreated() + " and the raius is " + radius); 44 } 45 }
1 package demo; 2 3 /** 4 * 矩形类,继承于几何类 5 * Created by luts on 2015/11/29. 6 */ 7 8 public class Rectangle extends GeometricObject{ 9 private double width; 10 private double height; 11 12 public Rectangle(){ 13 14 } 15 16 public Rectangle(String name, double newWidth, double newHeight){ 17 this.setName(name); 18 this.width = newWidth; 19 this.height = newHeight; 20 } 21 22 public Rectangle(double newWidth, double newHeight, String newColor, boolean newFilled){ 23 this.width = newWidth; 24 this.height = newHeight; 25 setColor(newColor); 26 setFilled(newFilled); 27 } 28 29 public double getWidth(){ 30 return width; 31 } 32 33 public void setWidth(double newWidth){ 34 this.width = newWidth; 35 } 36 37 public double getHeight(){ 38 return height; 39 } 40 41 public void setHeight(double newHeight){ 42 this.height = newHeight; 43 } 44 45 public double getArea(){ 46 return width * height; 47 } 48 49 public double getPerimeter(){ 50 return 2 * (width + height); 51 } 52 }
1 package demo; 2 3 /** 4 * Created by luts on 2015/11/29. 5 */ 6 7 public class TestGeometericObject { 8 public static void main(String[] args){ 9 GeometricObject geoObject1 = new Circle("Circle",5); //多态 父类类型指向子类实例的引用 10 GeometricObject geoObject2 = new Rectangle("Rectangle", 5, 3); 11 12 System.out.println("The two objects have the same area ?" + equalsArea(geoObject1, geoObject2)); 13 14 displayGeometricObject(geoObject1); 15 16 displayGeometricObject(geoObject2); 17 } 18 19 20 public static boolean equalsArea(GeometricObject obj1, GeometricObject obj2){ 21 return obj1.getArea() == obj2.getArea(); 22 } 23 24 public static void displayGeometricObject(GeometricObject object){ 25 System.out.println(); 26 System.out.println("The new " + object.getName()+ "‘s area is: " + object.getArea()); 27 System.out.println("The new " + object.getName()+ "‘perimeter is: " + object.getPerimeter()); 28 } 29 }
输出:
The two objects have the same area ?false The new Circle‘s area is: 78.53981633974483 The new Circle‘perimeter is: 31.41592653589793 The new Rectangle‘s area is: 15.0 The new Rectangle‘perimeter is: 16.0
上述例子中,如果GeometricObject 类中没有定义getArea()方法,就不能在程序中定义equalsArea方法来计算这两个几何对象的面积是否相等。JVM根据运行时的实际对象动态地调用getArea方法(多态)。
· 抽象类与常规类很相似,但是不能使用new操作符创建其实例对象,可以声明引用变量。
· 抽象方法只有定义没有实现,子类提供具体的实现方式。一个包含抽象方法的类必须声明为抽象类。
· 抽象类的构造方法定义为protected,因为只能被子类使用。创建一个具体的子类的时候,其父类的构造方法被调用,以初始化父类中定义的数据域。
一些值得注意的:
· 抽象方法不能包含在非抽象类中。如果抽象父类的子类不能实现所以的抽象方法,那么子类也应该声明为抽象类。也就是说在抽象类扩展的子类中,必须实现所有的抽象方法。抽象方法是非静态的。
· 抽象类不能使用new操作符来初始化。但是仍然可以定义其构造方法,这个构造方法在子类中被调用。
· 即使父类是具体的,这个子类也可以是抽象。例如Object是具体的,但是它的子类如上例中的GeometricObject可以是抽象的。
· 子类可以覆盖父类的方法并将其定义为abstract。也就是当父类的方法在子类的方法实现是没有意义的时候,可以将其覆盖声明为抽象方法,这时子类必须定义为abstract。
· 不能使用new操作符从一个抽象类创建一个实例,但是抽象类可以作为一种数据类型。
接口(interface)是一种与类相似的结构,只包含常量和抽象方法,目的是指明多个对象的共同行为。(比如,通过使用正确的接口,可以指明这些对象是可比较的,可食用的或可克隆的)。
接口的语法结构:
1 修饰符 interface 接口名{ 2 //常量名 3 //方法签名 4 } 5 6
7 public interfaceEdibleInterface{
8 public abstract String howToEat();
9 }
· 接口被看成是一种特殊的类,与抽象类类似,不能使用new操作符创建接口实例,可以使用接口作为变量的数据类型或类型转换的结果等。
例子:使用接口EdibleInterface来明确一个对象是否可食用。需要使用implements关键字让对象的类实现这个接口。类和接口之间的关系成为接口继承(interface inheritance)。
1 package demo; 2 3 /** 4 * Created by luts on 2015/11/30. 5 */ 6 public abstract interface EdibleInterface { 7 //Describe hoe to eat 8 public abstract String howToEat(); 9 }
1 package demo; 2 3 import java.util.Objects; 4 5 /** 6 * Created by luts on 2015/11/30. 7 */ 8 public class TestEdible { 9 public static void main(String[] args){ 10 Object[] objects = {new Tiger(), new Chicken(), new Apple()}; 11 for (int i = 0; i < objects.length; i++){ 12 if (objects[i] instanceof EdibleInterface) 13 System.out.println(((EdibleInterface) objects[i]).howToEat()); 14 } 15 } 16 } 17 18 class Animal{ 19 private String name; 20 21 public String getName() { 22 return name; 23 } 24 25 public void setName(String name) { 26 this.name = name; 27 } 28 } 29 30 class Chicken extends Animal implements EdibleInterface{ 31 public String howToEat(){ 32 return "Chiken: Fry it"; 33 } 34 } 35 36 class Tiger extends Animal { 37 38 } 39 40 abstract class Firut implements EdibleInterface{ 41 42 } 43 44 class Apple extends Firut{ 45 @Override 46 public String howToEat() { 47 return "Apple: Make apple cider"; 48 } 49 }
· 当一个类实现接口的时候,该类实现了定义在接口中的所有带确切签名和返回值类型的方法。如果继承接口的类不实现抽象方法,那么必须声明为抽象类,如abstract Fruit类。
· 接口中所有的数据域都是public final static。所有的方法都是public abstract,java允许忽略这些修饰符。
· 接口内定义的常量可以使用语法“接口名.常量名”来访问。
ActionListener接口例子:
1 package demo; 2 3 import javax.swing.*; 4 import java.awt.event.ActionEvent; 5 import java.awt.event.ActionListener; 6 7 /** 8 * Created by luts on 2015/11/30. 9 */ 10 public class HandleEvent extends JFrame{ 11 public HandleEvent(){ 12 //创建两个按钮 13 JButton jbtOK = new JButton("OK"); 14 JButton jbtCancel = new JButton("Cancel"); 15 16 JPanel panel = new JPanel(); 17 panel.add(jbtOK); 18 panel.add(jbtCancel); 19 20 add(panel); 21 22 OKListenerClass listener1 = new OKListenerClass(); 23 CancelListenrClass listener2 = new CancelListenrClass(); 24 jbtOK.addActionListener(listener1); 25 jbtCancel.addActionListener(listener2); 26 27 } 28 29 public static void main(String [] args){ 30 JFrame frame = new HandleEvent(); 31 frame.setTitle("Handle Event"); 32 frame.setSize(200, 150); 33 frame.setLocation(200, 100); 34 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 35 frame.setVisible(true); 36 } 37 } 38 39 class OKListenerClass implements ActionListener{ 40 public void actionPerformed(ActionEvent e){ 41 System.out.println("OK button clicked"); 42 } 43 } 44 45 class CancelListenrClass implements ActionListener{ 46 public void actionPerformed(ActionEvent e){ 47 System.out.println("Cancel button clicked"); 48 } 49 }
输出:
Cancel button clicked
Cancel button clicked
OK button clicked
Cancel button clicked
OK button clicked
OK button clicked
变量 | 构造方法 | 方法 | |
抽象类 | 无限制 | 子类通过构造方法链调用构造方法,抽象类不能使用new操作符实例化 | 无限制(可为抽象方法或非抽象方法),一般都含有抽象方法 |
接口 | 所有变量必须是 public static final | 没有构造方法,接口不能用new操作符实例化 | 所有方法必须是公共的抽象实例方法 |
· java只允许为类的扩展做单一的继承,但是允许使用接口做多重扩展。
public class NewClass extends BaseClass implements Interface1, ..., InterfaceN{ .... }
· 利用关键字extends,接口可以继承其他接口。这样的接口称为子接口(subinterface)。
public interface NewInterface extends Interface1, ..., InterfaceN{ ..... }
一个类实现上述的NewInterface必须实现Interface1, ..., InterfaceN中定义的所有抽象方法。接口可以扩展其他接口,但不能扩展类,一个类可以扩展它的父类同时实现多个接口。
· 所有类共享同一个根类Object,但是接口没有共同的根。
· 与类类似,接口也可以定义一种类型。一个接口类型的变量可以引用任何实现该接口的类的实例。也就是,一个类如果实现了一个接口,那么这个接口就类似于该类的一个父类。
接口和抽象类都是用来确定多个对象的共同特征的。那么什么时候使用接口,什么时候使用抽象类呢?
一般来说,详细描述父子关系的强是关系(strong is-a relationship)应该用类建模。弱是关系(weak is-a relationship)也称为类属关系(is-kind-relationship),它表明对象拥有某种属性。弱是关系可以用接口来建模。
原文:http://www.cnblogs.com/luts/p/5004982.html