前言
本文簡單介紹抽象類,介面以及它們的異同點,另附簡單的代碼舉例,
一、抽象類是什么?
在 Java 語言中使用 abstract class 來定義抽象類,抽象類是不能被實體化的,即不能用new關鍵字來實體化物件,包含抽象方法的一定是抽象類,但抽象類不一定包含抽象方法,如果一個子類實作了父類(抽象類)的所有抽象方法,那么該子類可以不必是抽象類,否則就是抽象類,抽象類中的抽象方法的修飾符只能為public或者protected,
為什么要在抽象類中定義抽象方法呢?下面我們來看一個代碼實體:
package example;
import java.util.Date;
public 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 boolean getFilled() {
return filled;
}
public void setFilled(boolean filled) {
this.filled=filled;
}
public java.util.Date getDateCreated(){
return dateCreated;
}
public abstract double getArea();//抽象方法定義得到面積
public abstract double getPerimeter();//抽象方法得到周長
}
我們假設自定義的Circle類和Rectangle類均為GeometricObject的子類,且均有求各自面積的getArea()方法和各自周長的getPerimeter()方法,但這些方法并不能在父類中定義,因為具體的計算方法要取決于幾何物件的具體型別,所以采取抽象方法進行定義,這樣可以保證父類中的抽象方法可以在子類中被重寫,
抽象類只有定義沒有實作,
下面是抽象類值得注意的幾點:
1.抽象方法不能包含在非抽象類中,如果抽象父類的子類不能實作所有的抽象方法,那么子類也必須定義為抽象的,也就是說,在繼承自抽象類的非抽象子類中,必須實作所有的抽象方法,還要注意到,抽象方法是靜態的,
2.抽象類不能使用new運算子來初始化,但仍然可以定義它的構造方法,這個構造方法在它的子類的構造方法中進行呼叫,
3.包含抽象方法的類必須是抽象的,但是是可以定義一個不包含抽象方法的抽象類,這個抽象類用于作為定義新子類的基類,
4.即使子類的父類是具體的,這個子類也可以是抽象的,
5.不能使用new運算子從一個抽象類創建一個實體,但是抽象類可以用做一種資料型別,
例如:GeometricObject[] objects=new GeometricObject[10];是正確的,,
6.子類可以重寫父類的方法并將它定義為抽象的,這雖然不常見,但很適用于當父類的方法實作在子類中變得無效時的情況,
二、介面是什么?
介面是一種與類很相似的結構,用于為物件定義共同操作,但它的目的是指明相關或者不相關類的物件的共同行為,
Java中介面使用interface關鍵字修飾,介面是抽象方法的集合,如果一個類實作了某個介面,那么它就繼承了這個介面的抽象方法,
類和介面之間的關系稱為介面繼承,
下面是簡單的代碼舉例:
package example;
public class TestEdible {
public static void main(String[] args) {
// TODO Auto-generated method stub
Object[] objects= {new Tiger(),new Chicken(),new Apple()};
//創建由Tiger,Chicken和Apple型別的三個物件構成的陣列
for(int i=0;i<objects.length;i++) {
if(objects[i] instanceof Edible)
System.out.println(((Edible)objects[i]).howToEat());
if(objects[i] instanceof Animal) {
System.out.println(((Animal)objects[i]).sound());
}
}//如果可食用,則呼叫howToEat方法,如果是動物,則呼叫sound方法
}
}
abstract class Animal{
private double weight;
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight=weight;
}
public abstract String sound();//回傳動物的聲音,是抽象方法,被具體的animal類實作
}
class Chicken extends Animal implements Edible{
@Override
public String howToEat() {
return "Chicken: Fry it";
}//實作了Edible介面,當一個類實作介面時,該類實作定義在介面中的所有方法,
@Override
public String sound() {
return "Chicken: cock-a-doodle-doo";
}
}
class Tiger extends Animal{
@Override
public String sound() {
return "Tiger:RROOAARR";
}
}
abstract class Fruit implements Edible{
}//Fruit類實作了Edible,但沒有實作howToEat方法,所以它必須定義為abstract,
class Apple extends Fruit{
@Override
public String howToEat() {
return "Apple:Make apple cider";
}
}//Fruit的具體子類必須實作howToEat方法,所以Apple類實作了howToEat方法,
需要注意的是,介面中所有的資料域都是public static final,而且所有方法都是public abstract,但Java允許忽略這些修飾符,
即下面的兩個代碼是等價的:
public interface T {
public static final int K=1;
public abstract void p();
}
public interface T {
int K=1;
void p();
}
盡管public修飾符對于定義在介面中的方法可以省略,但是在子類實作中方法必須定義為public,
三、抽象類和介面的異同點
一個類可以實作多個介面,但是只能繼承一個父類,
首先我們先來列舉個表格簡單講述一下抽象類和介面之間的異同點:
| 比較點 | 抽象類 | 介面 |
| 關鍵字 | abstract class | interface |
| 欄位 | 無限制 | 變數必須是public static final |
| 方法 | 既可以含普通方法,又可以含抽象方法,無限制 | 只能含抽象方法,且必須是public的 |
| 繼承/實作 | 只能被類或抽象類繼承 | 既可以被介面繼承,也能被類或抽象類實作 |
| 多重繼承 | 不支持 | 可以繼承多個父介面 |
java只允許為類的繼承做單一繼承,但是允許使用介面做多重繼承,例如:
public class NewClass extends BaseClass implements Interface1,...,InterfaceN{
}
利用extends,介面可以繼承其他介面,這樣的介面被稱為子介面,例如:下面的代碼中,NewInterface是Interface1,...,InterfaceN的子介面,
public interface NewInterface extends Interface1,...,InterfaceN{
}
一個實作NewInterface的類必須實作在NewInterface,Interface1,...,InterfaceN中定義的抽象方法,介面可以繼承其他介面但不能繼承類,一個類可以繼承它的父類同時實作多個介面,
所有的類都有一個共同的根類Object,但是介面并沒有共同的根,與類相似,介面同樣也可以定義一種型別,一個介面型別的變數可以參考任何實作該介面的類的實體,如果一個類實作了一個介面,那么這個介面就類似于該類的一個父類,可以將介面當作一種資料型別使用,將介面型別的變數轉換為它的子類,反過來同樣可以,
通常情況下,使用介面的頻率更高,因為介面比類更加靈活,不用使所有東西都屬于同一個型別的類,
下面進行一個簡單的代碼舉例:
abstract class Animal{
public abstract String howToEat();
}//在Animal中定義howToEat方法
//Animal的兩個子類定義如下
class Chicken extends Animal{
@Override
public String howToEat() {
return "Chicken: Fry it";
}
}
class Duck extends Animal{
@Override
public String howToEat() {
return "Roast it";
}
}
public static void main(String[] args) {
Animal animal = new Chicken();
eat(animal);
Animal animal = new Duck();
eat(animal);
}
public static void eat(Animal animal){
System.out.println(animal.howToEat());
}
假設給定這個繼承結構,java在呼叫方法時可以根據物件動態地決定呼叫具體的howToEat方法,但有一個限制條件,即該子類必須是另一種動物才可以,如果一種動物不可食用,那么此刻再繼承Animal類就并不合適了,
限制條件這個問題在介面中可以被解決,例如:
public class Demo{
public static void main(String[] args) {
Edible stuff = new Chicken();
eat(stuff);
Edible stuff = new Broccoli();
eat(stuff);
}
public static void eat(Edible stuff){
System.out.println(stuff.howToEat());
}
}
interface Edible{
public String howToEat();
}
class Chicken implements Edible{
@Override
public String howToEat() {
return "Chicken: Fry it";
}
}
class Broccoli implements Edible{
@Override
public String howToEat() {
return "Broccoli: Stir-fty it";
}
}
定義表示可食用物件的一個類,只須讓該類實作Edible介面即可,任何Edible物件都可以被傳遞以呼叫HowToEat方法,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/385579.html
標籤:java
下一篇:java網路編程
