抽象類與接口
##本博客講述了抽象類和接口以及它們的區別。每一個知識點之後都有相應的代碼演示。歡迎大家進行補充##
1. 抽象類
在Java中所有的對象都是通過類來描繪的,但是,並不是所有的類都是用來描繪對象的,
如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。
當發現多個類中有共有的方法時,可以將他們抽象出來,例如,狗和狼都會叫這一行爲,而且它們都
屬於犬科類,所以將這一行爲抽象出來,定義犬科爲抽象類。狗和狼均繼承犬科類,並覆蓋其方法。
在子類中具體實現。
具體實現代碼1:
package 抽象類;
abstract class 犬科{
abstract void 叫();//抽象函數,需要用abstract修飾,用分號結束。
}
class Dog extends 犬科{
void 叫(){
System.out.println("汪汪汪 ");
}
}
class Wolf extends 犬科{
void 叫(){
System.out.println("吼吼吼");
}
}
public class AbstractDemo1 {
public static void main(String[] args) {
Dog dog = new Dog();
dog.叫();
Wolf wolf = new Wolf();
wolf.叫();
}
}
具體實現2:
`public abstract class Animal {
public abstract void cry();
}
public class Cat extends Animal{
@Override
public void cry() {
System.out.println("貓叫:喵喵...");
}
}
public class Dog extends Animal{
@Override
public void cry() {
System.out.println("狗叫:汪汪...");
}
}
public class Test {
public static void main(String[] args) {
Animal a1 = new Cat();
Animal a2 = new Dog()
a1.cry();
a2.cry();
}
}`
注意:
1. 抽象類和抽象方法必須由abstract關鍵字指定。抽象方法一定要定義在抽象類中。
2. 抽象類不可以創建實例(即不能new對象)
原因:調用抽象方法沒有意義。所以抽象類必須被繼承。
3. 只有覆蓋了抽象類中所有的抽象方法後,其子類纔可以實例化。否則該子類還是一個抽象類。
4. 任何子類必須重寫父類中的所有抽象方法,否則聲明自身爲抽象類。
細節:
1.抽象類一定是一個父類?
是的,因爲抽象類是不斷抽取而來的。
2.抽象類是否有構造方法?
有,雖然抽象類不能給自己的對象初始化,但是可以給自己的子類對象初始化,
3.抽象類和一般類的異同點:
相同:
1.都是用來描述事物的。
2.它們之中都可以定義屬性和行爲。
不同:
1.一般類可以具體的描述事物;抽象類描述事物的信息不具體。
2.抽象類中可以多定義一個成員:抽象函數。
3.一般類可以創建對象,而抽象類不能創建對象。
3.抽象類中是否可以不定義抽象方法?
可以的,此時的意義僅僅是不讓該類創建對象。
4.抽象關鍵字abstract不可以和哪些關鍵字共存?
1)final 修飾的類不能有子類,而抽象類必須有子類。
2)private 私有的,也不能被覆蓋
3)static 靜態方法隨着類的加載而加載。
案例分析:
`package 抽象類;
/*
*需求:公司中程序員有姓名,工號,薪水,工作內容
* 項目經理除了有姓名,工號。薪水。還有獎金,工作內容,
*
*分析:
* 程序員
* 屬性:姓名 工號 薪水
* 行爲:工作(code...)
* 經理:
* 屬性: 姓名 工號 薪水 獎金
* 行爲: 工作(manage...)
*
* 所以 抽象類爲員工Employee
*
*/
//員工抽象類
abstract class Employee{
private String name;
private int id;
private double pay;
public Employee(String name,int id,double pay){
this.name = name;
this.id = id;
this.pay = pay;
}
@Override
public String toString() {
return "Employee [name=" + name + ", id=" + id + ", pay=" + pay + "]";
}
abstract void work();
}
//程序員
class Programmer extends Employee{
public Programmer(String name, int id, double pay) {
super(name, id, pay);//調用父類的構造方法
}
void work(){
System.out.println("code....");
}
}
class Manager extends Employee{
private double award;
public Manager(String name, int id, double pay,double award) {
super(name, id, pay);
this.award = award;
}
void work(){
System.out.println("manage...");
}
}
public class AbstractDemo2 {
public static void main(String[] args) {
Programmer programmer = new Programmer("小曾", 2, 10000);
System.out.println(programmer);
programmer.work();
}
}`
2. 接口
當一個抽象類中的方法全是抽象的時候,此時用另一種特殊的形式體現。用interface關鍵字定義
接口是用來建立類與類之間的協議,它所提供的只是一種形式,而沒有具體的實現。
接口是抽象類的延伸
接口是隱式抽象的,當聲明一個接口的時候,不必使用abstract關鍵字。
接口中每一個方法也是隱式抽象的,聲明時同樣不需要abstract關鍵字。
interface Animal {
public void eat();
public void travel();
}
接口的特點
1.接口無法被實例化,但是可以被實現。一個實現接口的類,必須實現接口內所描述的所有方法,否則就必須聲明爲抽象類
2.子類必須覆蓋接口中所有的抽象方法後,子類纔可以實例化。
3.接口中不存在具體的實現的方法
4.接口沒有構造方法。
5.接口中所有的方法必須是抽象方法。
6.變量必須有固定的修飾符修飾,public static final 所以接口中的變量也稱爲常量
7.方法必須有固定的修飾符,public abstract ,所以接口中的成員都是公共的。
8.接口支持多繼承。
具體代碼1:
`package 接口;
/*
* 定義一個接口,接口中可以有成員變量和方法
* 注意:
* 變量:變量必須有固定的修飾符修飾,public static final 所以接口中的變量也稱爲常量
* 方法:方法必須有固定的修飾符,public abstract ,所以接口中的成員都是公共的。
*/
interface Demo{
public static final int NUM = 6;
public abstract void show1();
public abstract void show2();
/*
* 也可以寫成此類型
* int NUM = 6;
* void show1();
* void show2();
*/
}
//類實現接口,並重寫接口中的方法
public class DemoImpl implements Demo{
@Override
public void show1() {
}
@Override
public void show2() {
}
}`
具體代碼2:
class D{
public void show(){};
interface A{
void show();
}
interface B{
void show();
}
class C extends D implements A,B{
public void show(){
}
}
接口的好處:
接口中的方法都沒有方法體,由子類來明確。接口可以多實現。
接口的出現避免了單繼承的侷限性;
父類中定義的事物的基本功能;接口中定義事物的擴展功能。
接口與接口是多繼承
在Java中,類的多繼承是不合法,但接口允許多繼承。
在接口的多繼承中extends關鍵字只需要使用一次,在其後跟着繼承接口。
代碼演示
interface interA{
void show1();
}
interface interAA{
void show11();
}
interface interB extends interA,interAA{//接口實現多繼承
void show2();
}
class Test implements interB{
@Override
public void show1() {}
@Override
public void show11() {}
@Override
public void show2() {}
}
沒有抽象方法的抽象類:抽象類中可以不定義抽象方法,原因僅是不讓該類創建對象。
代碼過程:
1.定義接口Inter(其中有四個抽象方法),類InterImpl1,InterImpl2 分別實現Inter接口,
`interface Inter{
//定義四種顯示功能
public void show1();
public void show2();
public void show3();
public void show4();
}
//定義一個類,要使用顯示第一種顯示方法
class InterImpl1 implements Inter{
@Override
public void show1() {
System.out.println("顯示第一種方式");
}
//爲了讓該類實例化,還需要覆蓋其他三個方法,
public void show2(){}
public void show3(){}
public void show4(){}
}
class InterImpl2 implements Inter{
@Override
public void show3() {
System.out.println("顯示第三種方式");
}
//爲了讓該類實例化,還需要覆蓋其他三個方法,
public void show2(){}
public void show1(){}
public void show4(){}
}
爲了使用接口中的部分方法,而覆蓋了全部的方法,而且每一個子類都要這麼做,複用性差。
所以
將這些不同的方法都單獨抽取到一個獨立的類中,讓這個類去實現接口,並覆蓋接口中所有的方法。
`abstract class InterDemoImpl implements Inter{
//重寫接口中所有的方法
@Override
public void show1() {
}
@Override
public void show2() {
}
@Override
public void show3() {
}
@Override
public void show4() {
}
}`
class InterImpl1 extends InterDemoImpl{
public void show1(){
System.out.println("顯示第一個方法");
}
}
class InterImpl2 extends InterDemoImpl{
public void show3(){
System.out.println("顯示第三個方法");
}
}
public class DemoImpll1 {
public static void main(String[] args) {
InterImpl1 impl1 = new InterImpl1();
impl1.show1();
InterImpl2 impl2 = new InterImpl2();
impl2.show3();
}
}
這個類並不知道具體的實現內容,都是空實現,不需要將此類創建對象,所以對其抽象化。
接口的設計思想
1.接口的出現對功能實現了擴展。
2.接口的出現定義了規則
3.接口的出現降低了耦合性。
接口和抽象類的區別
事件描述:
犬:假如按照功能分類:導盲犬,緝毒犬。。。
行爲:
吼叫();
吃飯();
abstract class 犬{
public abstract void 吼叫();
public abstract void 吃飯();
}
abstract class 緝毒{
public abstract void 緝毒();
}
class 緝毒犬 extends 犬{
@Override
public void 吼叫() {
}
@Override
public void 吃飯() {
}
public void 緝毒(){
}
}
//其他的動物可能也會有緝毒功能,無法實現多繼承,當犬是接口,緝毒也是接口時,可以多實現。但是類負責描述的是事物的基本功能,接口負責描述事物的擴展功能。所以,犬可以描述爲類,緝毒可以描述爲接口。
所以 以上代碼改爲:
abstract class 犬{
public abstract void 吼叫();
public abstract void 吃飯();
}
interface 緝毒{
public abstract void 緝毒();
}
class 緝毒犬 extends 犬 implements 緝毒{
@Override
public void 吼叫() { }
@Override
public void 吃飯() { }
public void 緝毒(){ }
}
抽象類與接口的區別:
1.抽象類是描述事物的基本功能,可以定義非抽象的方法;接口中的定義的方法是抽象的。
2.類與類之間是繼承關係,類與接口是實現關係。
3.抽象類中的方法可以有方法體,就是能實現方法的具體功能,但是接口中的方法不行。
4.抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是 public static final 類型的。
5.接口中不能含有靜態代碼塊以及靜態方法(用 static 修飾的方法),而抽象類是可以有靜態代碼塊和靜態方法。
6.一個類只能繼承一個抽象類,而一個類卻可以實現多個接口。
擴展
對於抽象類而言,它是自下而上來設計的,我們要先知道子類才能抽象出父類,而接口則不同,它根
本就不需要知道子類的存在,只需要定義一個規則即可,至於什麼子類、什麼時候怎麼實現它一概不
知。比如我們只有一個貓類在這裏,如果你這是就抽象成一個動物類,是不是設計有點兒過度?我們
起碼要有兩個動物類,貓、狗在這裏,我們在抽象他們的共同點形成動物抽象類吧!所以說抽象類往
往都是通過重構而來的!但是接口就不同,比如說飛,我們根本就不知道會有什麼東西來實現這個飛
接口,怎麼實現也不得而知,我們要做的就是事前定義好飛的行爲接口。所以說抽象類是自底向上抽
象而來的,接口是自頂向下設計出來的。