在展示范例之前,先介绍一些相关的概念和注意点,这是抽象类和接口的基础预备知识。
在继承的层次结构中,随着每个新子类的出现,类会变的越来越明确和具体。如果从一个子类追溯到父类,类就会变得更通用、更加不明确。类的设计应该确保父类包含子类的共同特征。
有时候,一个父类设计的非常抽象,以至于它没有任何具体的实例。这样的类称为抽象类。
抽象类中不实现,只声明的方法称为抽象方法。在方法头中用abstract修饰符表示。在类头使用abstract修饰符表示该类为抽象类。在UML类图中,抽象类和方法的名字用斜体表示。
抽象类和常规类很像,但是不能使用new操作符创建它的实例。抽象方法只有定义而没有实现。它的实现由子类提供。一个包含抽象方法的类必须声明为抽象类。
抽象类的构造方法定义为protected,因为它只被子类使用。创建一个具体子类的实例时,它的父类构造方法被调用以初始化父类中定义的数据域。
关于抽象类的几个注意点:
1)抽象方法不能包含在非抽象类中。如果抽象父类的子类不能实现所有的抽象方法,那么子类必须定义为抽象的。换句话说,在抽象类扩展的非抽象类中,必须实现所有的抽象方法。并且,抽象方法是非静态的。
2)包含抽象对象的类必须是抽象的。但是,可以定义一个不包含抽象方法的抽象类。在这种情况下,不能使用new操作符创建该类的实例。这种类是用来定义新子类的基类的。
3)即使子类的父类是具体的,这个子类也可以是抽象的。
4)子类可以覆盖父类的方法并将它定义为abstract。这是很少见的,但是它在当父类的方法实现在子类中变得不合法时是很有用的。在这种情况下,子类必须定义为abstract。
5)不能使用new操作符从一个抽象类创建一个实例,但是抽象类可以用作一种数据类型。
接口是一种与类相似的结构,只包含常量和抽象方法。它在很多方面都与抽象类很相似,但是它的目的是指明多个对象的共同行为。如,使用正确的接口,可以指明这些对象是可以比较的、可食用的或可克隆的。
Java中,接口被看作是一种特殊的类。就像常规类一样,每个接口都被编译为独立的字节码文件。与抽象类相似,不能使用new操作符创建接口的实例,但是大多数情况下,使用接口或多或少有点像使用抽象类。如可以使用接口作为引用变量的数据类型或类型转换的结果等等。
接口和抽象类的区别
或多或少可以使用和抽象类一样的方式使用接口,但是定义一个接口和定义一个抽象类有所不同,如下表所示:
接口可以扩展其他接口而不是类。一个类可以扩展它的父类同时实现多个接口 。
所有的类共享同一个根类Object,但是接口没有共同的根。与类类似,接口也可以定义一种类型。一个接口类型的变量可以引用任何实现该接口的类的实例。如果一个类实现了一个接口,那么这个接口就类似于该类的一个父类。可以将接口当作一种数据类型使用,将接口类型的变量转换成他的子类,反过来也可以。
运行效果如图:
实现的源代码如下所示:
package Blog;
public class blogTryProject {
public static void main(String[] args) {
TestChouXiang tcx = new TestChouXiang();
tcx.main(args);
}
}
//抽象类测试程序
class TestChouXiang{
public static void main(String[]args){
Rectangle rt = new Rectangle(4,5);
System.out.println(rt.toString());
System.out.println("Rectangle 的面积为:"+rt.getArea());
System.out.println("Rectangle 的周长为:"+rt.getPerimeter());
Circle c = new Circle(3);
System.out.println(c.toString());
System.out.println("Circle 的面积为:"+c.getArea());
System.out.println("Circle 的周长为:"+c.getPerimeter());
}
}
//抽象类GeometricObject
abstract class GeometricObject{
private String color = "White";
private boolean filled;
private java.util.Date dateCreated;
protected GeometricObject(){
dateCreated = new java.util.Date();
}
protected GeometricObject(String color,boolean filled){
dateCreated = new java.util.Date();
this.color = color;
this.filled = filled;
}
public String getColor(){
return color;
}
public void setColor(String color){
this.color = color;
}
public void setFilled(boolean filled){
this.filled = filled;
}
public java.util.Date getDateCreated(){
return dateCreated;
}
public String toString(){
return "created on "+dateCreated+"\ncolor: "+color+"\t\tfilled: "+filled;
}
public abstract double getArea();
public abstract double getPerimeter();
}
//矩形类
class Rectangle extends GeometricObject{
private double width;
private double height;
public Rectangle(){
}
public Rectangle(double width,double height){
this.width = width;
this.height = height;
}
public Rectangle(double width,double height,String color,boolean filled){
this.width = width;
this.height = height;
setColor(color);
setFilled(filled);
}
public double getWidth(){
return width;
}
public void setWidth(double width){
this.width = width;
}
public double getHeight(){
return height;
}
public void setHeight(double height){
this.height = height;
}
public double getArea(){
return width * height;
}
public double getPerimeter(){
return 2 * (width + height);
}
public String toString(){
return super.toString()+"\n宽为:"+getWidth()+"\t\t长为:"+getHeight();
}
}
//圆类
class Circle extends GeometricObject{
private double radius;
public Circle(){
}
public Circle(double radius){
this.radius = radius;
}
public Circle(double radius,String color,boolean filled){
this.radius = radius;
setColor(color);//这里不能用this.color = color;因为它是父类的私有数据域,在GeometricObject
//类外只能通过访问器和修改器对它进行操作
setFilled(filled);
}
public double getRadius(){
return radius;
}
public void setRadius(double radius){
this.radius = radius;
}
public double getArea(){
return radius * radius * Math.PI;
}
public double getPerimeter() {
return 2 * radius * Math.PI;
}
public double getDiameter(){
return 2 * radius;
}
public String toString(){
return super.toString()+"\n半径为: "+radius;
}
}
范例二:接口的简单范例。
运行效果如图所示:
实现的源代码如下所示:
package Blog;
public class blogTryProject {
public static void main(String[] args) {
TestEdible te = new TestEdible();
te.main(args);
}
}
//接口的简单范例
interface Edible{
public abstract String howToEat();
}
class TestEdible{
public static void main(String[]args){
Object[] objects = {new Tiger(),new Chicken(),new Apple(),new Orange()};
for(int i = 0;i < objects.length;i++)
if(objects[i] instanceof Edible)
System.out.println(((Edible)objects[i]).howToEat());
}
}
class Animal{
}
class Chicken extends Animal implements Edible{
public String howToEat(){
return "Chicken: Fry it";
}
}
class Tiger extends Animal{
}
abstract class Fruit implements Edible{
}
class Apple extends Fruit{
public String howToEat(){
return "Apple: Make apple cider";
}
}
class Orange extends Fruit{
public String howToEat(){
return "Orange: Make orange juice";
}
}
范例三:监听器接口(ActionListener),克隆接口(Cloneable),可比较接口(Comparable)。
ActionListener
运行效果如图所示:
实现的源代码如下所示:
package Blog;
import javax.swing.*;
public class blogTryProject {
public static void main(String[] args) {
HandleEvent he = new HandleEvent();
he.main(args);
}
}
//ActionListener监听器接口
class HandleEvent extends JFrame{
public HandleEvent(){
JButton jbtOk = new JButton("Ok");
JButton jbtCancel = new JButton("Cancel");
JPanel p = new JPanel();
p.add(jbtOk);
p.add(jbtCancel);
add(p);
OkListenerClass listener1 = new OkListenerClass();
CancelListenerClass listener2 = new CancelListenerClass();
//条件二:使用source.addActionListener(listener)注册源对象
jbtOk.addActionListener(listener1);
jbtCancel.addActionListener(listener2);
}
public static void main(String[]args){
JFrame frame = new HandleEvent();
frame.setTitle("Handle Event");
frame.setSize(200, 150);
frame.setLocation(200, 100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
//条件一:使得OkListenerClass成为监听器类的实例,并实现其方法
class OkListenerClass implements java.awt.event.ActionListener{
//事件actionPerformed方法的实现
public void actionPerformed(java.awt.event.ActionEvent e){
System.out.println("Ok button clicked");
}
}
class CancelListenerClass implements java.awt.event.ActionListener{
public void actionPerformed(java.awt.event.ActionEvent e){
System.out.println("Cancel button clicked");
}
}
Cloneable(注意克隆不成功会有异常抛出,可参考《Java基本功练习十八》)
运行效果如图所示:
实现的源代码如下所示:
package Blog;
public class blogTryProject {
public static void main(String[] args) throws CloneNotSupportedException {
House house = new House(12,89);
house.main(args);
}
}
//Cloneable接口范例
class House implements Cloneable,Comparable{
private int id;
private double area;
private java.util.Date whenBuilt;
public House(int id,double area){
this.id = id;
this.area = area;
whenBuilt = new java.util.Date();
}
public int getId(){
return id;
}
public double getArea(){
return area;
}
public java.util.Date getWhenBuilt(){
return whenBuilt;
}
//覆盖Object中保护类型的clone()方法,并增强其可见性为public
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
public int compareTo(Object o){
if(area > ((House)o).area)
return 1;
else if(area < ((House)o).area)
return -1;
else
return 0;
}
public String toString(){
return "House的信息,ID为:"+id+"\t面积为:"+area;
}
public boolean equals(Object o){
if(id == ((House)o).id && area == ((House)o).area)
return true;
else
return false;
}
public static void main(String[]args) throws CloneNotSupportedException{
House house1 = new House(502, 123);
House house2 = new House(503, 223);
House house3 = (House)house1.clone();
System.out.println("house1的信息为:"+house1.toString());
System.out.println("house2的信息为:"+house2.toString());
System.out.println("house3的信息为:"+house3.toString());
System.out.println("house1 与 house2 的面积大小比较:"+house1.compareTo(house2));
System.out.println("house1 与 house3 是否内容相同? "+house1.equals(house3));
System.out.println("house1 与 house3 是否引用变量相同? "+(house1 == house3));
}
}
Comparable
运行效果如图所示:
实现的源代码如下所示:
package Blog;
public class blogTryProject {
public static void main(String[] args){
TestComparableRectangle tcr = new TestComparableRectangle();
tcr.main(args);
}
}
//Comparable接口实现范例
/*
Comparable的接口定义如下
package java.lang;
public interface Comparable{
public int compareTo(Object o);
}
*/
class ComparableRectangle extends Rectangle implements Comparable{
//构造函数
public ComparableRectangle(double width,double height){
super(width,height);
}
//Comparable接口的实现
public int compareTo(Object o){
if(getArea() > ((ComparableRectangle)o).getArea())
return 1;
else if(getArea() < ((ComparableRectangle)o).getArea())
return -1;
else
return 0;
}
//利用接口新定义一个比较两个矩形面积的静态方法
public static Comparable max(Comparable o1,Comparable o2){
if(o1.compareTo(o2) > 0)
return o1;
else
return o2;
}
}
//测试Comparable接口程序
class TestComparableRectangle{
public static void main(String[]args){
ComparableRectangle tcr1 = new ComparableRectangle(2, 5);
ComparableRectangle tcr2 = new ComparableRectangle(3, 6);
System.out.println("\nComparable接口演示范例");
System.out.println("两个矩形的信息如下");
System.out.println(tcr1.toString());
System.out.println(tcr2.toString());
System.out.println("tcr1 和 tcr2 比较结果为:"+tcr1.compareTo(tcr2));
System.out.println("面积大者的信息如下\n"+tcr1.max(tcr1, tcr2));
}
}
//矩形类
class Rectangle extends GeometricObject{
private double width;
private double height;
public Rectangle(){
}
public Rectangle(double width,double height){
this.width = width;
this.height = height;
}
public Rectangle(double width,double height,String color,boolean filled){
this.width = width;
this.height = height;
setColor(color);
setFilled(filled);
}
public double getWidth(){
return width;
}
public void setWidth(double width){
this.width = width;
}
public double getHeight(){
return height;
}
public void setHeight(double height){
this.height = height;
}
public double getArea(){
return width * height;
}
public double getPerimeter(){
return 2 * (width + height);
}
public String toString(){
return super.toString()+"\n宽为:"+getWidth()+"\t\t长为:"+getHeight();
}
}
//抽象类GeometricObject
abstract class GeometricObject{
private String color = "White";
private boolean filled;
private java.util.Date dateCreated;
protected GeometricObject(){
dateCreated = new java.util.Date();
}
protected GeometricObject(String color,boolean filled){
dateCreated = new java.util.Date();
this.color = color;
this.filled = filled;
}
public String getColor(){
return color;
}
public void setColor(String color){
this.color = color;
}
public void setFilled(boolean filled){
this.filled = filled;
}
public java.util.Date getDateCreated(){
return dateCreated;
}
public String toString(){
return "created on "+dateCreated+"\ncolor: "+color+"\t\tfilled: "+filled;
}
public abstract double getArea();
public abstract double getPerimeter();
}
范例四:包装类范例。Java提供一个方便的办法,将基本数据类型并入对象或包装成对象,称为包装类。
运行效果如图所示:
实现的源代码如下所示:
package Blog;
public class blogTryProject {
public static void main(String[] args){
GenericSort gc = new GenericSort();
gc.main(args);
}
}
//对象数组排序范例
class GenericSort{
public static void main(String[]args){
System.out.println("对象数组排序范例");
Integer[] intArray = {new Integer(2),new Integer(4),new Integer(3)};
Double[] doubleArray = {new Double(3.4),new Double(1.3),new Double(-22.1)};
Character[] charArray = {new Character('a'),new Character('J'),new Character('r')};
String[] stringArray = {"Tom","John","Fred"};
sort(intArray);
sort(doubleArray);
sort(charArray);
sort(stringArray);
System.out.println("Sorted Integer objects:");
printList(intArray);
System.out.println("Sorted Double objects:");
printList(doubleArray);
System.out.println("Sorted Character objects:");
printList(charArray);
System.out.println("Sorted String objects:");
printList(stringArray);
}
public static void sort(Comparable[] list){
Comparable currentMin;
int currentMinIndex;
for(int i = 0;i < list.length - 1;i++){
currentMin = list[i];
currentMinIndex = i;
for(int j = i + 1;j < list.length;j++){
if(currentMin.compareTo(list[j]) > 0){
currentMin = list[j];
currentMinIndex = j;
}
}
if(currentMinIndex != i){
list[currentMinIndex] = list[i];
list[i] = currentMin;
}
}
}
public static void printList(Object[] list){
for(int i = 0;i < list.length;i++)
System.out.print(list[i]+" ");
System.out.println();
}
}
范例五:有理数类的加减乘除实现。
运行效果如图所示:
实现的源代码如下所示:
package Blog;
public class blogTryProject {
public static void main(String[] args){
TestRational tr = new TestRational();
tr.main(args);
}
}
//有理数类测试
class TestRational{
public static void main(String[]args){
Rational r1 = new Rational(4,2);
Rational r2 = new Rational(2,3);
System.out.println(r1+" + "+r2+" = "+r1.add(r2));
System.out.println(r1+" - "+r2+" = "+r1.subtract(r2));
System.out.println(r1+" * "+r2+" = "+r1.multiply(r2));
System.out.println(r1+" / "+r2+" = "+r1.divide(r2));
System.out.println(r2+" is "+r2.doubleValue());
}
}
//有理数类实现
class Rational extends Number implements Comparable{
private long numerator = 0;
private long denominator = 1;
public Rational(){
this(0,1);
}
public Rational(long numerator,long denominator){
long gcd = gcd(numerator,denominator);
this.numerator = ((denominator > 0) ? 1 : -1) * numerator / gcd;
this.denominator = Math.abs(denominator) / gcd;
}
private static long gcd(long n,long d){
long n1 = Math.abs(n);
long n2 = Math.abs(d);
int gcd = 1;
for(int k = 1;k <= n1 && k <= n2;k++){
if(n1 % k == 0 && n2 % k == 0)
gcd = k;
}
return gcd;
}
public long getNumerator(){
return numerator;
}
public long getDenominator(){
return denominator;
}
public Rational add(Rational secondRational){
long n = numerator * secondRational.getDenominator() +
denominator * secondRational.getNumerator();
long d = denominator * secondRational.getDenominator();
return new Rational(n,d);
}
public Rational subtract(Rational secondRational){
long n = numerator * secondRational.getDenominator() -
denominator * secondRational.getNumerator();
long d = denominator * secondRational.getDenominator();
return new Rational(n,d);
}
public Rational multiply(Rational secondRational){
long n = numerator * secondRational.getNumerator();
long d = denominator * secondRational.getDenominator();
return new Rational(n,d);
}
public Rational divide(Rational secondRational){
long n = numerator * secondRational.getDenominator();
long d = denominator * secondRational.numerator;
return new Rational(n,d);
}
public String toString(){
if(denominator == 1)
return numerator +"";
else
return numerator+"/"+denominator;
}
public boolean equals(Object parm1){
if((this.subtract((Rational)(parm1))).getNumerator() == 0)
return true;
else
return false;
}
public int intValue(){
return (int)doubleValue();
}
public float floatValue(){
return (float)doubleValue();
}
public double doubleValue(){
return numerator * 1.0 / denominator;
}
public long longValue(){
return (long)doubleValue();
}
public int compareTo(Object o){
if((this.subtract((Rational)o)).getNumerator() > 0)
return 1;
else if((this.subtract((Rational)o)).getNumerator() < 0)
return -1;
else
return 0;
}
}
范例六:接口和抽象类简单实例的实现对比。
运行效果如图所示:
实现的源代码如下所示:
package Blog;
public class blogTryProject {
public static void main(String[] args){
ChouXiangAnimal cxa = new ChouXiangAnimal();
cxa.main(args);
JieKouAnimal jka = new JieKouAnimal();
jka.main(args);
}
}
//接口和抽象类的优劣比较
//抽象类实现的方式
class ChouXiangAnimal{
public static void main(String[]args){
//抽象类实现Animal
System.out.println("抽象类实现Animal");
NewAnimal animal = new NewChicken();
eat(animal);
animal = new Duck();
eat(animal);
}
public static void eat(NewAnimal animal){
System.out.println(animal.howToEat());
}
}
abstract class NewAnimal{
public abstract String howToEat();
}
class NewChicken extends NewAnimal{
public String howToEat(){
return "NewChicken: Fry it";
}
}
class Duck extends NewAnimal{
public String howToEat(){
return "Duck: Roast it";
}
}
//接口实现方式
class JieKouAnimal{
public static void main(String[]args){
//接口实现的Animal
System.out.println("接口实现的Animal");
NewEdible stuff = new NewChicken1();
eat(stuff);
stuff = new Duck1();
eat(stuff);
stuff = new Broccoli();
eat(stuff);
}
public static void eat(NewEdible stuff){
System.out.println(stuff.howToEat());
}
}
interface NewEdible{
public String howToEat();
}
class NewChicken1 implements NewEdible{
public String howToEat(){
return "NewChicken1: Fry it";
}
}
class Duck1 implements NewEdible{
public String howToEat(){
return "Duck1: Fry it";
}
}
class Broccoli implements NewEdible{
public String howToEat(){
return "Broccoli: Stir-fry it";
}
}