java基礎個人筆記之抽象類,介面與多型,內部類
抽象類:
抽象:籠統,模糊,看不懂!不具體。
特點:
1,方法只有宣告沒有實現時,該方法就是抽象方法,需要被abstract修飾。
抽象方法必須定義在抽象類中。該類必須也被abstract修飾。
2,抽象類不可以被例項化。為什麼?因為呼叫抽象方法沒意義。
3,抽象類必須有其子類覆蓋了所有的抽象方法後,該子類才可以例項化。
否則,這個子類還是抽象類。
1,抽象類中有建構函式嗎?
有,用於給子類物件進行初始化。
2,抽象類可以不定義抽象方法嗎?
可以的。 但是很少見,目的就是不讓該類建立物件。AWT的介面卡物件就是這種類。
通常這個類中的方法有方法體,但是卻沒有內容。
3,抽象關鍵字不可以和那些關鍵字共存?
private 不行
static 不行
final 不行
4,抽象類和一般類的異同點。
相同點:
抽象類和一般類都是用來描述事物的,都在內部定了成員。
不同:
1,一般類有足夠的資訊描述事物。
抽象類描述事物的資訊有可能不足。
2,一般類中不能定義抽象方法,只能定非抽象方法。
抽象類中可定義抽象方法,同時也可以定義非抽象方法。
3,一般類可以被例項化。
抽象類不可以被例項化。
5,抽象類一定是個父類嗎?
是的。因為需要子類覆蓋其方法後才可以對子類例項化。
abstract class AbsDemo
{
abstract void show1();
abstract void show2();
}
當一個抽象類中的方法都是抽象的時候,這時可以將該抽象類用
另一種形式定義和表示,就是 介面 interface。
//定義介面使用的關鍵字不是class,是interface.
對於介面當中常見的成員:而且這些成員都有固定的修飾符。
1,全域性常量: public static final (修飾符不寫會自動補全)
2,抽象方法。public abstract
由此得出結論,介面中的成員都是公共的許可權.
interface Demo
{
public static final int NUM = 4;
public abstract void show1();
public abstract void show2();
}
//類與類之間是繼承關係,類與介面直接是實現關係。
介面不可以例項化。
只能由實現了介面的子類並覆蓋了介面中所有的抽象方法後,該子類才可以例項化。
否則,這個子類就是一個抽象類。
class DemoImpl implements /*實現*/Demo
{
public void show1()
{}
public void show2()
{
}
}
在java中不直接支援多繼承,因為會出現呼叫的不確定性。
所以java將多繼承機制進行改良,在java中變成了多實現。
一個類可以實現多個介面。 介面的出現避免了單繼承的侷限性。
抽象類和介面的異同點:
相同點:
都是不斷向上抽取而來的。
不同點:
1,抽象類需要被繼承,而且只能單繼承。
介面需要被實現,而且可以多實現。
2,抽象類中可以定義抽象方法和非抽象方法,子類繼承後,可以直接使用非抽象方法。
介面中只能定義抽象方法,必須由子類去實現。
3,抽象類的繼承,是is a關係,在定義該體系的基本共性內容。
介面的實現是 like a 關係,在定義體系額外功能。
例子:犬按功能分:有導盲犬,搜爆犬。
abstract class 犬 //基本功能
{
abstract void 吼叫();
}
interface 導盲 //額外功能
{
abstract void 導盲();
}
class 導盲犬 extends 犬 implements 導盲
{
public void 吼叫()
{
}
public void 導盲(){}
}
物件的多型性。
class 動物
{}
class 貓 extends 動物
{}
class 狗 extends 動物
{}
貓 x = new 貓();
動物 x = new 貓();//一個物件,兩種形態。
貓這類事物即具備者貓的形態,又具備著動物的形態。
這就是物件的多型性。
簡單說:就是一個物件對應著不同型別.
多型在程式碼中的體現:
父類或者介面的引用指向其子類的物件。
多型的好處:
提高了程式碼的擴充套件性,前期定義的程式碼可以使用後期的內容。
多型的弊端:
前期定義的內容不能使用(呼叫)後期子類的特有內容。
多型的前提:
1,必須有關係,繼承,實現。
2,要有覆蓋。
畢老師和畢姥爺的故事。
class 畢姥爺
{
void 講課()
{
System.out.println("管理");
}
void 釣魚()
{
System.out.println("釣魚");
}
}
class 畢老師 extends 畢姥爺
{
void 講課()
{
System.out.println("Java");
}
void 看電影()
{
System.out.println("看電影");
}
}
class DuoTaiDemo2
{
public static void main(String[] args)
{
// 畢老師 x = new 畢老師();
// x.講課();
// x.看電影();
畢姥爺 x = new 畢老師();//多型,自動型別提升,老師物件提升了姥爺型別。但是隻能訪問畢姥爺的方法(外部看到的是畢姥爺(本身是畢老師),若畢姥爺和畢老師有方法一樣,使用的是畢老師的方法),無法使用畢老師特有的方法。
//作用就是限制對特有功能的訪問。
//專業講:向上轉型。將子型別隱藏。就不用使用子類的特有方法。
x.講課();
x.釣魚();
畢老師 y = (畢老師)x;//如果想用畢老師的特有功能,你可以將該物件進行向下轉型。
//向下轉型的目的是為了使用子類中的特有方法。
// 注意:對於轉型,自始自終都是子類物件在做著型別的變化。
y.看電影();
}
}
//a instanceof People//instanceof:用於判斷物件的具體型別。只能用於引用資料型別判斷 //通常在向下轉型前用於健壯性的判斷。
多型時
成員的特點:
1,成員變數。
編譯時:參考引用型變數所屬的類中的是否有呼叫的成員變數,有,編譯通過,沒有,編譯失敗。
執行時:參考引用型變數所屬的類中的是否有呼叫的成員變數,並執行該所屬類中的成員變數。
簡單說:編譯和執行都參考等號的左邊。
2,成員函式(非靜態)。
編譯時:參考引用型變數所屬的類中的是否有呼叫的函式。有,編譯通過,沒有,編譯失敗。
執行時:參考的是物件所屬的類中是否有呼叫的函式。
簡單說:編譯看左邊,執行看右邊。
因為成員函式存在覆蓋特性。
3,靜態函式。
編譯時:參考引用型變數所屬的類中的是否有呼叫的靜態方法。
執行時:參考引用型變數所屬的類中的是否有呼叫的靜態方法。
簡單說,編譯和執行都看左邊。
其實對於靜態方法,是不需要物件的。直接用類名呼叫即可。
內部類訪問特點:
1,內部類可以直接訪問外部類中的成員。
為什麼內部類能直接訪問外部類中成員呢?
那是因為內部類持有了外部類的引用。 外部類名.this
2,外部類要訪問內部類,必須建立內部類的物件。
一般用於類的設計。
分析事物時,發現該事物描述中還有事物,而且這個事物還在訪問被描述事物的內容。
這時就是還有的事物定義成內部類來描述。
class InnerClassDemo
{
public static void main(String[] args)
{
// Outer out = new Outer();
// out.method();
//直接訪問外部類中的內部類中的成員。
// Outer.Inner in = new Outer().new Inner();
// in.show();
//如果內部類是靜態的。 相當於一個外部類
// Outer.Inner in = new Outer.Inner();
// in.show();
//static void function()//如果內部類中定義了靜態成員,該內部類也必須是靜態的。
//如果內部類是靜態的,成員也得是靜態的。
// Outer.Inner.function();
}
}
內部類可以存放在區域性位置上。
內部類在區域性位置上只能訪問區域性中被final修飾的區域性變數。
class Outer
{
int num = 3;
Object method()
{
final int x = 9;
class Inner
{
public String toString()
{
return "show ..."+x;//內部類在區域性位置上只能訪問區域性中被final修飾的區域性變數。
}
}
Object in = new Inner();
return in;//0x0045
// in.show();
}
}
class InnerClassDemo3
{
public static void main(String[] args)
{
Outer out = new Outer();
Object obj = out.method();
System.out.println(obj);
}
}
/*
class Fu extends Object
{}
class zi extends Fu
{}
Fu f = new zi();
Object o = new Fu();
匿名內部類。就是內部類的簡寫格式。
必須有前提:
內部類必須繼承或者實現一個外部類或者介面。
匿名內部類:其實就是一個匿名子類物件。
格式:new 父類or介面(){子類內容}
通常的使用場景之一:
當函式引數是介面型別時,而且介面中的方法不超過三個。
可以用匿名內部類作為實際引數進行傳遞
class Outer
{
void method()
{
/*new Object()
{
public void show()
{
System.out.println("show run");
}
}.show()//執行通過;*/
Object obj = new Object()
{
public void show()
{
System.out.println("show run");
}
};
obj.show();//因為匿名內部類這個子類物件被向上轉型為了Object型別。
//這樣就不能在使用子類特有的方法了。obj沒有show方法
}
}
class InnerClassDemo6
{
public static void main(String[] args)
{
new Outer().method();
}
}
例項化物件執行的順序::首先執行建構函式中預設的super()父類初始化父類=》然後初始化當前物件=》最後執行建構函式中的程式碼