3.1、抽象類與接口(☆)
抽象類更多的情況下是作爲一個模板使用,而接口更多的情況下是作爲一個標準出現。
3.1.1 、適配器設計
一個子類如果實現了一個接口,則肯定要覆寫接口中的全部方法,那是否有一種方式,可以讓子類有選擇的去實現接口中的方法,而不是全都實現呢?
interface A{
public void printA() ;
public void printB() ;
public void printC() ;
public void printD() ;
public void printE() ;
} |
以上的接口的子類能否有選擇性的進行所需要方法的覆寫呢?
interface A{
public void printA() ;
public void printB() ;
public void printC() ;
public void printD() ;
public void printE() ;
}
abstract class AAdapter implements A{
// 方法全部實現
// 但是此類是中間過渡類,不能直接使用,所以此時應該把此類定義成抽象類。
public void printA() {}
public void printB() {}
public void printC() {}
public void printD() {}
public void printE() {}
};
class AAA extends AA{
public void printA() {
System.out.println("dafa");
}
}; |
思考:
張三去酒會參加活動,碰見了一個美國女孩,想跟她說“HELLO,MAKE FRIEND”,第二次又參加了一個舞會,又碰見了一箇中國的女孩,想跟她說“你好,我想跟你交朋友”。
· 碰見美國人說英語
· 碰見中國人說中文
· 接口的第二個作用就是表示一種能力。
interface SayChina{
public void sayChina() ;
}
interface SayEnglish{
public void sayEnglish() ;
}
class Person implements SayChina,SayEnglish{
public void sayChina(){
System.out.println("你好,交朋友吧!") ;
}
public void sayEnglish(){
System.out.println("HELLO,MAKE FRIEND!") ;
}
}; |
3.1.2 、代理設計
思考:
現在孫鍵欠了我500000000元錢,此時,王寧是一個老實人,孫鍵欺負他,不還,之後王寧沒有辦法了,找到了王偉(專門的討債公司),準備好了繩索、刀子、槍支,從孫鍵手裏把銀子要了回來,之後銷燬了一切的證據。但是王寧只管拿回了自己的錢。
可以按照以下的形式組織代碼:
interface Subject{
public void giveMoney() ;
}
class RealSubject implements Subject{
public void giveMoney(){
System.out.println("把錢拿回。。。") ;
}
};
class ProxySubject implements Subject{
private Subject sub = null ;
public ProxySubject(Subject sub){
this.sub = sub ;
}
public void before(){
System.out.println("要準備繩索、刀子、槍支。。。") ;
}
public void giveMoney(){
this.before() ;
this.sub.giveMoney() ;
this.after() ;
}
public void after(){
System.out.println("銷燬一切的罪證。。。") ;
}
};
public class Demo06{
public static void main(String args[]){
Subject sub = new ProxySubject(new RealSubject()) ;
sub.giveMoney() ;
}
}; |
3.1.3 、工廠設計
問題的引出:現在使用一個接口,同時定義出子類,通過子類爲接口進行實例化:
interface Fruit{
public void eat() ;
}
class Apple implements Fruit{
public void eat(){
System.out.println("吃蘋果。。。") ;
}
};
public class Demo07{
public static void main(String args[]){
Fruit f = new Apple() ;
f.eat() ;
}
}; |
以上代碼存在問題?
· main方法實際上相當於是一個客戶端程序
· 如果現在需要換一個子類了,那麼就要修改客戶端。
· 好的程序:某一處的更改不影響調用處
造成以上問題的根源:
· 子類直接在客戶端使用,耦合度太深了。
在對象實例化的中間加入一個過渡端,所謂的解耦合最大的特點就是永遠有一個過渡端。
那麼現在加入一個過渡端:
interface Fruit{
public void eat() ;
}
class Apple implements Fruit{
public void eat(){
System.out.println("吃蘋果。。。") ;
}
};
class Cherry implements Fruit{
public void eat(){
System.out.println("吃櫻桃。。。") ;
}
};
class Factory{
public static Fruit getInstance(String str){
Fruit f = null ;
if("apple".equals(str)){
f = new Apple() ;
}
if("cherry".equals(str)){
f = new Cherry() ;
}
return f ;
}
};
public class Demo08{
public static void main(String args[]){
Fruit f = Factory.getInstance(args[0]) ;
if(f!=null)
f.eat() ;
}
}; |
此時,發現程序的客戶端沒有任何的改變,而直接可以選擇各種所要的子類。那麼通過工廠取得全部的接口實例,那麼以後修改的時候就可以只修改工廠了。
3.1.4 、抽象類與接口的區別(☆☆)
區別點 |
抽象類 |
接口 |
定義 |
abstract class 抽象類名稱{} |
interface 接口名稱{} |
概念 |
包含一個抽象方法的類就是抽象類,除此之外還包含常量、變量、普通方法、構造方法 |
只包含全局常量和抽象方法的類稱爲接口 |
使用 |
需要通過子類繼承
class 子類 extends 父類 |
需要通過子類實現
class 子類 implements 接口 |
關係 |
一個抽象類可以實現多個接口,一個接口不能繼承一個抽象類 | |
作用 |
提供了一個模板 |
提供了一個標準,或者說表示了一種能力 |
設計模式 |
模板設計模式 |
工廠設計模式、代理設計模式 |
適配器設計模式 | ||
限制 |
抽象類有單繼承侷限 |
無此侷限 |
應用 |
如果抽象類與接口同時都可以使用,優先使用接口 | |
特殊點 |
一個抽象類可以包含一個接口或一個抽象類 |
一個接口中也可以包含抽象類或接口 |
特殊點:
1、 一個抽象類中能否包含一個接口?可以
abstract class A{
public abstract void printA() ;
interface B{
public void printB() ;
}
};
class DA extends A{
public void printA(){}
class DB implements B{
public void printB(){}
};
}; |
2、 一個接口中能否包含一個抽象類?可以
interface A{
public abstract void printA() ;
abstract class B{
public abstract void printB() ;
}
};
class DA implements A{
public void printA(){}
class DB extends B{
public void printB(){}
};
}; |
觀察以下的題目,寫出輸出結果:
abstract class A{
public A(){
this.print() ;
}
public abstract void print() ;
}
class B extends A{
private int i = 10 ;
public B(int i){
this.i = i ;
}
public void print(){
System.out.println(this.i) ;
}
};
public class Demo11{
public static void main(String artgs[]){
new B(100) ;
}
}; |
答案是0
子類對象實例化之前,肯定要先去調用父類中的無參構造方法,爲父類中的屬性初始化,但是父類中的方法未調用完之前,子類的內容並沒有初始化,如果沒有初始化,則會安排默認值,默認值就是“0” 。