抽象類(abstract)
一個類只定義了一個為所有子類共享的一般形式,至於細節則交給每一個子類去實現,這種類沒有任何具體的實例,只具有一些抽象的概念,那么這樣的類稱為抽象類。
在面向對象領域,抽象類主要用來進行類型隱藏。比如,如果我們進行一個圖形編輯軟件的開發,就會發現問題領域存在着圓、三角形這樣一些具體概念,它們是不同的,但是它們都屬於形狀這樣一個概念,形狀這個概念在問題領域是不存在的,它就是一個抽象概念。正是因為抽象概念在問題領域沒有對應的具體概念,所以用以表征抽象概念的抽象類是不能夠實例化的。
abstract class class_name
{
abstract type method_name(parameter);
}
abstract 表示該類或該方法是抽象的;class_name 表示抽象類的名稱;method_name 表示抽象方法名稱,如果在一個方法之前使用 abstract 來修飾,則說明該方法是抽象方法,不能有方法體;parameter 表示方法參數列表。
abstract 關鍵字只能用於普通方法,不能用於 static 方法或者構造方法中。在抽象類中必須包含至少一個抽象方法,並且所有抽象方法不能有具體的實現,而應在它們的子類中實現所有的抽象方法(要有方法體),包含一個或多個抽象方法的類必須通過在其 class 聲明前添加 abstract 關鍵字將其聲明為抽象類。因為一個抽象類不定義完整的實現,所以抽象類也就沒有自己的對象。因此,任何使用 new 創建抽象類對象的嘗試都會導致編譯時錯誤。
public abstract class Shape
{
public int width; //幾何圖形的長
public int height; //幾何圖形的寬
public Shape(int width,int height)
{
this.width=width;
this.height=height;
}
public abstract double area(); //定義抽象方法,計算面積
}
public class Square extends Shape
{
public Square(int width,int height)
{
super(width,height);
}
@Override
public double area()//重寫父類中的抽象方法,實現計算正方形面積的功能
{
return width*height;
}
}
public static void main(String[] args)
{
Square square=new Square(5,4);
System.out.println("面積為:"+square.area());//輸出:面積為:20
}
接口
接口類似於類,但接口的成員沒有執行體,它只是方法、屬性、事件和索引符的組合而已。接口不能被實例化,接口沒有構造方法,沒有字段。在應用程序中,接口就是一種規范,它封裝了可以被多個類繼承的公共部分。
接口繼承和實現繼承的規則不同,一個類只有一個直接父類,但可以實現多個接口。Java 接口本身沒有任何實現,只描述 public 行為,因此 Java 接口比 Java 抽象類更抽象化。Java 接口的方法只能是抽象的和公開的,Java 接口不能有構造方法,Java 接口可以有 public、Static 和 final 屬性。
接口把方法的特征和方法的實現分隔開來,這種分隔體現在接口常常代表一個角色,它包裝與該角色相關的操作和屬性,而實現這個接口的類便是扮演這個角色的演員。一個角色由不同的演員來演,而不同的演員之間除了扮演一個共同的角色之外,並不要求其他的共同之處。
接口對於其聲明、變量和方法都做了許多限制,這些限制作為接口的特征歸納如下:
具有 public 訪問控制符的接口,允許任何類使用;沒有指定 public 的接口,其訪問將局限於所屬的包。
方法的聲明不需要其他修飾符,在接口中聲明的方法,將隱式地聲明為公有的(public)和抽象的(abstract)。
在 Java 接口中聲明的變量其實都是常量,接口中的變量聲明,將隱式地聲明為 public、static 和 final,即常量,所以接口中定義的變量必須初始化。接口沒有構造方法,不能被實例化。
定義
public interface interfaceName{
}
//例如
public interface Personlnterface{
String name; //不合法,變量name必須初始化
int age=20; //合法,等同於 public static final int age=20;
void getInfo(); //方法聲明,等同於 public abstract void getInfo();
}
實現
在實現類中,所有的方法都使用了 public 訪問修飾符聲明。無論何時實現一個由接口定義的方法,它都必須實現為 public,因為接口中的所有成員都顯式聲明為 public
public class Person implements Personlnterface
{
public void getInfo(){
return "Hello World";
}
}
使用
public static void main(String[] args){
Personlnterface person = new Person();
person.getInfo();//返回 HelloWorld
}
抽象類與接口的區別
在面向對象的設計思想中,所有的對象都是通過類來描繪的,但是反過來,並不是所有的類都是用來描繪對象的,如果一個類中沒有描繪一個具體的對象,那么這樣的類就是抽象類,抽象類是對那些看上去不同,但是本質上相同的具體概念的抽象,正是因為抽象的概念在問題領域沒有對應的具體概念,所以抽象類是不能夠實例化的
語法不同
接口內只能是功能的定義,而抽象類中則可以包括功能的定義和功能的實現。在接口中,所有的屬性肯定是 public、static 和 final,所有的方法都是 abstract,所以可以默認不寫上述標識符;在抽象類中,既可以包含抽象的定義,也可以包含具體的實現方法
public interface Animal
{
public void eat();
public String fly();
}
public abstract class Animal
{
public abstract void eat();
public String fly(){
return "我會飛";
};
}
接口的實現類中使用 implements 關鍵字;而在抽象類的實現類中,則使用 extends 關鍵字。一個接口的實現類可以實現多個接口,而一個抽象類的實現類則只能實現一個抽象類。
//接口
public class concreteAnimal implements Animal
{
public void eat(){}
public void fly(){}
}
//抽象類
public class concreteAnimal extends Animal
{
public void eat(){}
public void fly(){}
}
設計思想不同
從前面抽象類的具體實現類的實現方式可以看出,其實在 Java 中,抽象類和具體實現類之間是一種繼承關系,也就是說如果釆用抽象類的方式,則父類和子類在概念上應該是相同的。接口卻不一樣,如果采用接口的方式,則父類和子類在概念上不要求相同。接口只是抽取相互之間沒有關系的類的共同特征,而不用關注類之間的關系,它可以使沒有層次關系的類具有相同的行為。因此,可以這樣說:抽象類是對一組具有相同屬性和方法的邏輯上有關系的事物的一種抽象,而接口則是對一組具有相同屬性和方法的邏輯上不相關的事物的一種抽象。
強列的is a 使用抽象類,has a 使用接口。如:鳥是一種動物。鳥有一個功能會飛。貓也是一種動物,但是貓不會飛。
//接口
public interface Fly
{
public void flyUp();
}
//抽象類
public abstract class Animal
{
public abstract void eat();
}
//貓是一種動物
public class Cat extends Animal{
}
//鳥是一種動物,同時會飛
public class Bird extends Animal implements Run {
}
抽象類是對一組具有相同屬性和方法的邏輯上有關系的事物的一種抽象,而接口則是對一組具有相同屬性和方法的邏輯上不相關的事物的一種抽象,因此抽象類表示的是“is a”關系,接口表示的是“has a”關系。
內部類
在一個類內部的類,我們稱之為內部類。內部類可以很好地實現隱藏,一般的非內部類是不允許有 private 與 protected 權限的,但內部類可以。內部類擁有外圍類的所有元素的訪問權限。
內部類可以分為:實例內部類、靜態內部類和成員內部類,每種內部類都有它特定的一些特點,本節先詳細介紹一些和內部類相關的知識。
內部類的特點如下:
內部類仍然是一個獨立的類,在編譯之后內部類會被編譯成獨立的 .class 文件,但是前面冠以外部類的類名和 $ 符號。
內部類不能用普通的方式訪問。內部類是外部類的一個成員,因此內部類可以自由地訪問外部類的成員變量,無論是否為 private 的。
內部類聲明成靜態的,就不能隨便訪問外部類的成員變量,仍然是只能訪問外部類的靜態成員變量。
public class Test
{
public class InnerClass
{
public int getSum(int x,int y)
{
return x+y;
}
}
public static void main(String[] args)
{
Test.InnerClass testInner =new Test().new InnerClass();
int i = testInner.getSum(2/3);
System.out.println(i); //輸出5
}
}
實例內部類
實例內部類是指沒有用 static 修飾的內部類
public class Outer
{
class Inner
{
//實例內部類
}
}
在外部類的靜態方法和外部類以外的其他類中,必須通過外部類的實例創建內部類的實例,如果有多層嵌套,則內部類可以訪問所有外部類的成員
public class Outer
{
class Inner{}
Inner i=new Inner(); //類內部不需要創建外部類實例
public void method0()
{
Inner j=new Inner(); //類內部不需要創建外部類實例
}
public static void method1()
{
Inner r=new Outer().new inner(); //靜態方法需要創建外部類實例
}
class Inner1
{
Inner k=new Inner(); //不需要創建外部類實例
}
}
class OtherClass
{
Outer.Inner i=new Outer().new Inner(); //其他類使用時需要創建外部類實例
}
靜態內部類
靜態內部類是指使用 static 修飾的內部類
public class Outer
{
static class Inner
{
//靜態內部類
}
}
在創建靜態內部類的實例時,不需要創建外部類的實例
public class Outer
{
static class Inner{}
}
class OtherClass
{
Outer.Inner oi=new Outer.Inner();
}
局部內部類
局部內部類是指在一個方法中定義的內部類
public class Test
{
public void method()
{
class Inner
{
//局部內部類
}
}
}
局部內部類與局部變量一樣,不能使用訪問控制修飾符(public、private 和 protected)和 static 修飾符修飾,局部內部類只在當前方法中有效,局部內部類中可以訪問外部類的所有成員
public class Test
{
Inner i=new Inner(); //編譯出錯
Test.Inner ti=new Test.Inner(); //編譯出錯
Test.Inner ti2=new Test().new Inner(); //編譯出錯
public void method()
{
class Inner{}
Inner i=new Inner();
}
}
匿名類
匿名類是指沒有類名的內部類,必須在創建時使用 new 語句來聲明類
new<類或接口>()
{
//類的主體
};
這種形式的 new 語句聲明一個新的匿名類,它對一個給定的類進行擴展,或者實現一個給定的接口。使用匿名類可使代碼更加簡潔、緊湊,模塊化程度更高
匿名類有兩種實現方式:
繼承一個類,重寫其方法。
實現一個接口(可以是多個),實現其方法。
public class Out
{
void show()
{
System.out.println("調用 Out 類的 show() 方法");
}
}
public class TestAnonymousInterClass
{
//在這個方法中構造一個匿名內部類
private void show()
{
Out anonyInter=new Out()
{
//獲取匿名內部類的實例
void show()
{
System.out.println("調用匿名類中的 show() 方法");
}
};
anonyInter.show();
}
public static void main(String[] args)
{
TestAnonymousInterClass test=new TestAnonymousInterClass();
test.show();
}
}