在展示範例之前,先介紹一些相關的概念和注意點,這是抽象類和接口的基礎預備知識。
在繼承的層次結構中,隨着每個新子類的出現,類會變的越來越明確和具體。如果從一個子類追溯到父類,類就會變得更通用、更加不明確。類的設計應該確保父類包含子類的共同特徵。
有時候,一個父類設計的非常抽象,以至於它沒有任何具體的實例。這樣的類稱爲抽象類。
抽象類中不實現,只聲明的方法稱爲抽象方法。在方法頭中用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";
}
}