抽象類
- 抽象類是從多個(gè)具體類中抽象出來的父類,它具有更高層次的抽象
- 從多個(gè)具有相同特征的類中抽象出一個(gè)抽象類,以這個(gè)抽象類作為其子類的模板,避免子類設(shè)計(jì)的隨意性。
有抽象方法的類只能被定義成抽象類,抽象類里可以沒有抽象方法
抽象類不能被實(shí)例化,只能當(dāng)作父類被繼承。
抽象類的編程
public abstract class shape {
public abstract double getArea();
/**
* 比較兩個(gè)形狀的大小
* @param p 另一個(gè)形狀的實(shí)例
* @return 如果當(dāng)前形狀較大則返回true
*/
public boolean compareArea(shape p){
return this.getArea()>p.getArea();
}
}
抽象方法作為父類申明了抽象的getArea()方法
public class Circle extends shape {
double redius;
public Circle(double redius){
this.redius =redius;
}
@Override
public double getArea() {
return Math.PI*redius*redius;
}
}
子類實(shí)現(xiàn)抽象類,重寫父類抽象方法
public class Reactanger extends shape {
double length;
public Reactanger(double length){
this.length=length;
}
@Override
public double getArea() {
return length*length;
}
}
創(chuàng)建子類對象,調(diào)用重寫方法,比較兩者的面積,進(jìn)行打印
public static void main(String[] args) {
shape cir = new Circle(2.33);
shape rea = new Reactanger(8.0);//此處用父類類型的引用變量和子類類型的引用變量一樣,因?yàn)槎际侵赶蜃宇悓ο? System.out.println(cir.getArea());
System.out.println(rea.getArea());
System.out.println(cir.compareArea(rea));
}
接口
接口概念
- 接口是功能的集合,同樣可看做是一種數(shù)據(jù)類型,是比抽象類更為抽象的”類”。
接口只描述所應(yīng)該具備的方法,并沒有具體實(shí)現(xiàn),具體的實(shí)現(xiàn)由接口的實(shí)現(xiàn)類(相當(dāng)于接口的子類)來完成。這樣將功能的定義與實(shí)現(xiàn)分離,優(yōu)化了程序設(shè)計(jì)。
請記?。阂磺惺挛锞泄δ?,即一切事物均有接口
接口的定義
- 與定義類的class不同,接口定義時(shí)需要使用interface關(guān)鍵字。
定義接口所在的仍為.java文件,雖然聲明時(shí)使用的為interface關(guān)鍵字的編譯后仍然會(huì)產(chǎn)生.class文件。這點(diǎn)可以讓我們將接口看做是一種只包含了功能聲明的特殊類。
定義格式
public interface 接口名 {
抽象方法1;
抽象方法2;
抽象方法3;
}
- ?接口中的方法均為公共訪問的抽象方法
?接口中無法定義普通的成員變量
類實(shí)現(xiàn)接口
- 類與接口的關(guān)系為實(shí)現(xiàn)關(guān)系,即類實(shí)現(xiàn)接口。實(shí)現(xiàn)的動(dòng)作類似繼承,只是關(guān)鍵字不同,實(shí)現(xiàn)使用implements。
其他類(實(shí)現(xiàn)類)實(shí)現(xiàn)接口后,就相當(dāng)于聲明:”我應(yīng)該具備這個(gè)接口中的功能”。實(shí)現(xiàn)類仍然需要重寫方法以實(shí)現(xiàn)具體的功能。
格式
class 類 implements 接口 {
重寫接口中方法
}
接口成員的特點(diǎn):
1、接口中可以定義變量,但是變量必須有固定的修飾符修飾,public static final 所以接口中的變量也稱之為常量,其值不能改變。
2、接口中可以定義方法,方法也有固定的修飾符,public abstract
3、接口不可以創(chuàng)建對象。
4、子類必須覆蓋掉接口中所有的抽象方法后,子類才可以實(shí)例化。否則子類是一個(gè)抽象類。
interface Demo { ///定義一個(gè)名稱為Demo的接口。
public static final int NUM = 3;// NUM的值不能改變
public abstract void show1();
public abstract void show2();
}
//定義子類去覆蓋接口中的方法。類與接口之間的關(guān)系是 實(shí)現(xiàn)。通過 關(guān)鍵字 implements
class DemoImpl implements Demo { //子類實(shí)現(xiàn)Demo接口。
//重寫接口中的方法。
public void show1(){}
public void show2(){}
}
接口的多實(shí)現(xiàn)
interface Fu1
{
void show1();
}
interface Fu2
{
void show2();
}
class Zi implements Fu1,Fu2// 多實(shí)現(xiàn)。同時(shí)實(shí)現(xiàn)多個(gè)接口。
{
public void show1(){}
public void show2(){}
}
- 怎么解決多繼承的弊端?
弊端:多繼承時(shí),當(dāng)多個(gè)父類中有相同功能時(shí),子類調(diào)用會(huì)產(chǎn)生不確定性。
其實(shí)核心原因就是在于多繼承父類中功能有主體,而導(dǎo)致調(diào)用運(yùn)行時(shí),不確定運(yùn)行哪個(gè)主體內(nèi)容。
為什么多實(shí)現(xiàn)能解決?
因?yàn)榻涌谥械墓δ芏紱]有方法體,由子類來明確。
類繼承類同時(shí)實(shí)現(xiàn)接口
1、接口和類之間可以通過實(shí)現(xiàn)產(chǎn)生關(guān)系,同時(shí)也學(xué)習(xí)了類與類之間可以通過繼承產(chǎn)生關(guān)系。當(dāng)一個(gè)類已經(jīng)繼承了一個(gè)父類,它又需要擴(kuò)展額外的功能,這時(shí)接口就派上用場了。
2、子類通過繼承父類擴(kuò)展功能,通過繼承擴(kuò)展的功能都是子類應(yīng)該具備的基礎(chǔ)功能。如果子類想要繼續(xù)擴(kuò)展其他類中的功能呢?這時(shí)通過實(shí)現(xiàn)接口來完成。
class Fu {
public void show(){}
}
interface Inter {
pulbic abstract void show1();
}
class Zi extends Fu implements Inter {
public void show1() {
}
}
- 學(xué)習(xí)類的時(shí)候,知道類與類之間可以通過繼承產(chǎn)生關(guān)系,接口和類之間可以通過實(shí)現(xiàn)產(chǎn)生關(guān)系,那么接口與接口之間會(huì)有什么關(guān)系。
多個(gè)接口之間可以使用extends進(jìn)行繼承。
interface Fu1{
void show();
}
interface Fu2{
void show1();
}
interface Fu3{
void show2();
}
interface Zi extends Fu1,Fu2,Fu3{
void show3();
}
內(nèi)部類
- 將類寫在其他類的內(nèi)部,可以寫在其他類的成員位置和局部位置,這時(shí)寫在其他類內(nèi)部的類就稱為內(nèi)部類。其他類也稱為外部類
什么時(shí)候使用內(nèi)部類
class 汽車 { //外部類
class 發(fā)動(dòng)機(jī) { //內(nèi)部類
}
}
內(nèi)部類可以直接訪問外部類的所有成員
成員內(nèi)部類
- 成員內(nèi)部類,定義在外部類中的成員位置。與類中的成員變量相似,可通過外部類對象進(jìn)行訪問
成員內(nèi)部類代碼演示
class Body {//外部類,身體
private boolean life= true; //生命狀態(tài)
public class Heart { //內(nèi)部類,心臟
public void jump() {
System.out.println("心臟噗通噗通的跳")
System.out.println("生命狀態(tài)" + life); //訪問外部類成員變量
}
}
}
訪問內(nèi)部類
public static void main(String[] args) {
//創(chuàng)建內(nèi)部類對象
Body.Heart bh = new Body().new Heart();
//調(diào)用內(nèi)部類中的方法
bh.jump();
}
- 不過要注意的是,當(dāng)成員內(nèi)部類擁有和外部類同名的成員變量或者方法時(shí),會(huì)發(fā)生隱藏現(xiàn)象,即默認(rèn)情況下訪問的是成員內(nèi)部類的成員。如果要訪問外部類的同名成員,需要以下面的形式進(jìn)行訪問:
1、外部類.this.成員變量
2、外部類.this.成員方法
局部內(nèi)部類
class 外部類 {
修飾符 返回值類型 方法名(參數(shù)) {
class 內(nèi)部類 {
//其他代碼
}
訪問內(nèi)部類
public static void main(String[] args) {
//創(chuàng)建外部類對象
Party p = new Party();
//調(diào)用外部類中的puffBall方法
p.puffBall();
}
匿名內(nèi)部類
代碼演示:
//已經(jīng)存在的父類:
public abstract class Person{
public abstract void eat();
}
//定義并創(chuàng)建該父類的子類對象,并用多態(tài)的方式賦值給父類引用變量
Person p = new Person(){
public void eat() {
System.out.println(“我吃了”);
}
};
//調(diào)用eat方法
p.eat();
使用匿名對象的方式,將定義子類與創(chuàng)建子類對象兩個(gè)步驟由一個(gè)格式一次完成,。雖然是兩個(gè)步驟,但是兩個(gè)步驟是連在一起完成的。
匿名內(nèi)部類如果不定義變量引用,則也是匿名對象。代碼如下:
new Person(){
public void eat() {
System.out.println(“我吃了”);
}
}.eat();
靜態(tài)內(nèi)部類
靜態(tài)內(nèi)部類也是定義在另一個(gè)類里面的類,只不過在類的前面多了一個(gè)關(guān)鍵字static。靜態(tài)內(nèi)部類是不需要依賴于外部類的,這點(diǎn)和類的靜態(tài)成員屬性有點(diǎn)類似,并且它不能使用外部類的非static成員變量或者方法,這點(diǎn)很好理解,因?yàn)樵跊]有外部類的對象的情況下,可以創(chuàng)建靜態(tài)內(nèi)部類的對象,如果允許訪問外部類的非static成員就會(huì)產(chǎn)生矛盾,因?yàn)橥獠款惖姆莝tatic成員必須依附于具體的對象。