一、繼承
當(dāng)兩個(gè)事物之間存在一定的所屬關(guān)系,即就像孩子從父母那里得到遺傳基因一樣,當(dāng)然,java要遺傳的更完美,這兩個(gè)類中,一個(gè)繼承的類(為子類或者基礎(chǔ)類)可以從被繼承的類(為父類或者超類)中獲得一些屬性和方法,而不必再自己創(chuàng)建新方法(在不需要復(fù)寫的情況等)。
1、特點(diǎn):
1、提高代碼復(fù)用性,定義在父類中的成員(變量和方法),可以被子類重復(fù)使用;
2、讓類與類之間產(chǎn)生關(guān)系,這樣就會(huì)有多態(tài)的特性。使得應(yīng)用起來(lái)更方便。
需要注意的是:
A.不可以只是為了獲取其他類的功能,簡(jiǎn)化代碼就一味的使用繼承;必須是類與類之間有所屬關(guān)系,才可以用繼承,這種關(guān)系稱為“is-a”。
B.java語(yǔ)言中,只支持單繼承,不支持多繼承。究其原因,是因?yàn)槎嗬^承容易帶來(lái)安全隱患:
a.當(dāng)多個(gè)父類中定義了相同的功能,且功能內(nèi)容不同時(shí),子類對(duì)象并不確定要運(yùn)行哪一個(gè),這就造成了程序的混亂而導(dǎo)致異常出現(xiàn)。
b但是java保留了這種機(jī)制,并改良了多繼承為多實(shí)現(xiàn),而且接口就可以多繼承。
2、使用繼承體系中的功能
1、如果使用體系,要先對(duì)體系中父類的描述進(jìn)行參閱,了解父類中的共性功能,即可以使用該體系了。這樣既可以減少查閱時(shí)間,也能更系統(tǒng)的了解體系結(jié)構(gòu),以及父類的功能。
2、具體調(diào)用父類中的功能的時(shí)候,需要?jiǎng)?chuàng)建子類對(duì)象,通過(guò)子類對(duì)象對(duì)父類方法調(diào)用,實(shí)現(xiàn)繼承。
為何要通過(guò)創(chuàng)建子類對(duì)象調(diào)用父類中的方法呢?原因如下:
a.父類很可能不可以創(chuàng)建對(duì)象,如父類是一個(gè)抽象類或者接口,這就需要子類創(chuàng)建對(duì)象,調(diào)用方法。
b.創(chuàng)建子類對(duì)象,可以使用更多的功能,如父類公有的,和子類中自定義的特有功能。
3、子父類出現(xiàn)后,類成員的特點(diǎn):
類成員:變量、函數(shù)、構(gòu)造函數(shù)
1、變量:
子父類中出現(xiàn)非私有的同名成員變量是,子類訪問(wèn)本類的同名時(shí),要用this關(guān)鍵字(如果省略了this,仍是代表本類的變量);子類訪問(wèn)父類同名變量時(shí),用super關(guān)鍵字。
補(bǔ)充:this和super兩者都存在與方法區(qū)中。
this:本類對(duì)象引用,那個(gè)對(duì)象調(diào)用this所在的函數(shù),this就代表那個(gè)對(duì)象。
super:父類對(duì)象引用,用于子類初始化父類構(gòu)造函數(shù)時(shí)等。
2、.函數(shù):(覆蓋(重寫))
當(dāng)子類同父類出現(xiàn)相同函數(shù)時(shí),子類對(duì)象調(diào)用該函數(shù)時(shí),會(huì)運(yùn)行子類內(nèi)容,如同覆蓋谷類函數(shù)一樣。實(shí)際上并沒(méi)有覆蓋父類的函數(shù),如果還需要調(diào)用父類的這個(gè)方法,需要用super.方法名即可。
舉例:
class Father
{
int num = 3;
void show()
{
System.out.println(num);
}
}
class Son extends Father
{
int num = 5;
//復(fù)寫父類函數(shù)
void show()
{
System.out.println(num);//this引用,此處省略this,結(jié)果是5
System.out.println(super.num);//super引用,結(jié)果是3.
}
}
class Demo
{
public static void main(String [] args)
{
Son s = new Son();
s.show();
}
}
在內(nèi)存中的加載方式:
Son中的對(duì)象加載之后,才會(huì)出現(xiàn)this和super。
應(yīng)用:
a.當(dāng)子類繼承父類時(shí),就沿襲了父類的功能,在子類中,雖然具備該功能,,但是其內(nèi)容卻與父類不同,此時(shí),可覆蓋父類的方法(即保留),使用新特性。
注意:
第一、子類權(quán)限必須大于或等于父類的才能覆蓋;
第二、靜態(tài)只能覆蓋靜態(tài)。
b.用于擴(kuò)展(新功能或內(nèi)容等)
示例如下:
class Father
{
void show()
{
System.out.println("Wathing TV");
}
}
class Son extends Father
{
//復(fù)寫父類函數(shù)
void show()
{
System.out.println("Wathing TV");//父類中的功能
System.out.println("Playing PC");//擴(kuò)展的功能
}
}
class Demo
{
public static void main(String [] args)
{
Son s = new Son();
s.show();
}
}
3、子父類構(gòu)造函數(shù):子類的構(gòu)造函數(shù)中有一個(gè)隱式的構(gòu)造函數(shù)
特點(diǎn):在對(duì)子類對(duì)象進(jìn)行初始化時(shí),父類構(gòu)造函數(shù)也在運(yùn)行,而且是在子類之前運(yùn)行。因?yàn)樽宇悩?gòu)造函數(shù)默認(rèn)第一行有一條隱式語(yǔ)句:super();(沒(méi)有顯式的繼承父類的類中,是默認(rèn)繼承Object的,所以構(gòu)造函數(shù)第一條語(yǔ)句仍是super();),因此會(huì)首先訪問(wèn)父類中空參數(shù)的構(gòu)造函數(shù)(在不手動(dòng)加入含有參數(shù)的super的語(yǔ)句的情況下),這是系統(tǒng)默認(rèn)的。所有的構(gòu)造函數(shù)均是如此。
需要注意的是:
a.如果父類中無(wú)空參數(shù)構(gòu)造函數(shù)(即父類中顯式的構(gòu)造了含有參數(shù)的構(gòu)造函數(shù)),必須手動(dòng)加入父類中該構(gòu)造函數(shù)。
b.構(gòu)造函數(shù)不存在覆蓋,子類中的構(gòu)造函數(shù)必定至少有一個(gè)會(huì)訪問(wèn)父類中的構(gòu)造函數(shù)。
舉例:
為什么子類一定要訪問(wèn)父類的構(gòu)造函數(shù)呢?
第一、由于父類中的數(shù)據(jù)可直接獲取,所以子類對(duì)象建立時(shí),需要先查看父類是如何對(duì)這些數(shù)據(jù)進(jìn)行初始化的。因此,子類在初始化的時(shí)候須先訪問(wèn)父類構(gòu)造函數(shù),如果父類對(duì)這些數(shù)據(jù)初始化后,可以使用,子類就無(wú)需在進(jìn)行多余的操作了。
第二、如果要訪問(wèn)指定的構(gòu)造函數(shù),可手動(dòng)定義super語(yǔ)句的方式來(lái)指定特定的構(gòu)造函數(shù)。
注意:
super語(yǔ)句一定要定義在子類構(gòu)造函數(shù)的第一條語(yǔ)句,即第一行,因?yàn)橐瘸跏蓟割悩?gòu)造函數(shù),然后再初始化子類構(gòu)造函數(shù),子類構(gòu)造函數(shù)判斷是否父類的可用,不可用則子類將其覆蓋掉,這樣子類在可以方便選擇。
構(gòu)造函數(shù)中,this和super語(yǔ)句都必須在第一語(yǔ)句出現(xiàn),因?yàn)閮烧叨际怯脕?lái)初始化的,既然是初始化,就要首先存在,就只能進(jìn)行一次,因此不能同時(shí)作為第一條語(yǔ)句出現(xiàn)。
總結(jié):子類實(shí)例化過(guò)程
1、子類所有的構(gòu)造函數(shù)默認(rèn)均訪問(wèn)父類中的空參數(shù)構(gòu)造函數(shù),因?yàn)樽宇惷總€(gè)構(gòu)造函數(shù)內(nèi)的第一行均有一句隱式的super();語(yǔ)句。
2、當(dāng)父類中悟空參數(shù)構(gòu)造函數(shù)時(shí),子類必須手動(dòng)通過(guò)super語(yǔ)句的形式指定要訪問(wèn)的父類中的構(gòu)造函數(shù)
3、子類構(gòu)造函數(shù)也可手動(dòng)指定this語(yǔ)句,來(lái)訪問(wèn)本類中的構(gòu)造函數(shù),但子類中至少要有一個(gè)構(gòu)造函數(shù)訪問(wèn)父類的構(gòu)造函數(shù)。
還有一個(gè)問(wèn)題,就是繼承是對(duì)封裝性的一個(gè)挑戰(zhàn),這個(gè)問(wèn)題是用final解決的。具體關(guān)于final在此不再贅述了。
二、內(nèi)部類
先來(lái)看一段簡(jiǎn)單的代碼:
//情況一:創(chuàng)建兩個(gè)常規(guī)類A和B
class A{
int a = 5;
void fun(){
C c = new C();
c.method();
System.out.println("A:" + a);
}
//情況二:將C類放入A類中
class C{
void method(){
System.out.println("C訪問(wèn)A:" + a);//可直接訪問(wèn)
}
}
}
class B{
void fu(){
int a = 6;
A me = new A();
System.out.println("訪問(wèn)A中a:" + me.a);//必須建立對(duì)象后才能訪問(wèn)
}
}
class Demo
{
public static void main(String[] args)
{
A x = new A();
B y = new B();
x.fun();
y.fu();
}
}
從代碼中就可以看出,內(nèi)部類的好處。
內(nèi)部類:將一個(gè)類定義在另一個(gè)類之中。
1、訪問(wèn)規(guī)則(即使用內(nèi)部類的好處):
1、內(nèi)部類方法可以訪問(wèn)該類所在的類中作用域的成員,包括私有成員變量。
2、內(nèi)部類可以對(duì)同一個(gè)包中的其他類隱藏起來(lái),從而不被訪問(wèn)
3、使用匿名內(nèi)部類是比較便捷簡(jiǎn)單的,這種情況較多的用于AWT設(shè)計(jì)中。
注:
為何內(nèi)部類可直接訪問(wèn)外部類:
由于成員可被對(duì)象訪問(wèn),內(nèi)部類中持有了一個(gè)外部類的引用,,因此就可以直接用:外部類名.this.成員
2、訪問(wèn)格式:
1當(dāng)內(nèi)部類定義在外部類的成員位置上,而且非私有,可在外部其他類中直接建立內(nèi)部類對(duì)象
格式:外部類名.內(nèi)部類名 變量名 = 外部類對(duì)象.內(nèi)部類對(duì)象
2、當(dāng)內(nèi)部類在成員變量的位置上,可被成員修飾符修飾
·private:將內(nèi)部類在外部類中進(jìn)行封裝
·static:內(nèi)部類具備了static的特性,當(dāng)內(nèi)部類被static修飾(下面說(shuō)到的靜態(tài)內(nèi)部類),只可訪問(wèn)外部類中的static的成員,訪問(wèn)則受限。
注:(Outer為外部類名,Inner為內(nèi)部類名,function為非靜態(tài)成員)
在其他類中,如何訪問(wèn)靜態(tài)內(nèi)部類中非靜態(tài)成員:new Outer.Inner.function();(建立對(duì)象訪問(wèn))
在其他類中,如何訪問(wèn)靜態(tài)內(nèi)部類中的靜態(tài)成員:Outer.Inner.function();(可直接訪問(wèn))
注意:
1、當(dāng)內(nèi)部類中定義了靜態(tài)成員,該內(nèi)部類必須為靜態(tài)的
2、當(dāng)外部類中靜態(tài)方法訪問(wèn)內(nèi)部類時(shí),內(nèi)部類必須為靜態(tài)的
3、內(nèi)部類一般定義為private的,而很少定義為public的。
3、內(nèi)部類定義原則:------->多在程序設(shè)計(jì)中使用
1、當(dāng)描述事物時(shí),事物的內(nèi)部還有事物,則該事物使用內(nèi)部類來(lái)描述,因?yàn)閮?nèi)部事物要使用外部事物內(nèi)容
舉例來(lái)說(shuō):
樓房?jī)?nèi)部還有家庭住戶,家庭住戶中還有房間,這就可以用內(nèi)部類描述。(總不能訪問(wèn)一個(gè)住戶,就建立一個(gè)樓房對(duì)象吧,那就可真是有錢人的風(fēng)范了。)
2、何時(shí)定義內(nèi)部類:
當(dāng)一個(gè)類需要直接訪問(wèn)另一個(gè)類中的成員時(shí),則當(dāng)這個(gè)類放入另一個(gè)類中,并將內(nèi)部類封裝。
3、內(nèi)部類生成文件:
我們?cè)诰幾g一個(gè)源文件是,如果代碼中有內(nèi)部類,你會(huì)發(fā)現(xiàn),生成的class文件中含有例如這樣的文件:A(美元符號(hào))分隔外部類名和內(nèi)部類名的常規(guī)類文件,而虛擬機(jī)對(duì)此卻一無(wú)所知。
4、局部?jī)?nèi)部類(也稱局部類,方法中)
看下面一段代碼:
class A{
private int a = 5;
void fun(){
class B{//在方法中創(chuàng)建一個(gè)內(nèi)部類
void method(){
System.out.println("C訪問(wèn)A:" + a);//可直接訪問(wèn)
}
}
B c = new B();//建立一個(gè)對(duì)象
c.method();
}
}
class Demo
{
public static void main(String[] args)
{
A x = new A();
x.fun();
}
}
局部?jī)?nèi)部類:當(dāng)內(nèi)部類只在外部類中的某個(gè)方法中,創(chuàng)建了這個(gè)類型的對(duì)象時(shí),且僅使用了一次,那么可在這個(gè)方法中定義局部類。
注:
1、局部?jī)?nèi)部類不可用public或者private訪問(wèn)修飾符聲明,它的作用域被限定在了聲明這個(gè)局部類的代碼塊中
2、局部類的優(yōu)勢(shì):
a.對(duì)外界完全隱藏,即使此方法所在的類也不可訪問(wèn),也就是說(shuō),除此方法外,無(wú)任何方法知道它的存在。
b.可訪問(wèn)包含他們的外部類,因還持有外部類的引用;還可訪問(wèn)局部變量,但是局部變量必須被聲明為final。
需要注意:局部?jī)?nèi)部類不可被成員修飾符修飾,如static
代碼如下:
/*
局部?jī)?nèi)部類測(cè)試:
*/
class Outer//類不能用private,但是內(nèi)部類是可以的
{
int x = 3;
private static class InnerOuter//可在外部類的任意有效的地方,可以用private和static
{ //......
}
//含局部變量時(shí)
void method(final int a)//需訪問(wèn)加final
{
final int y = 4;//y需要被聲明為最終類型,即final才可被局部?jī)?nèi)部類中的成員訪問(wèn)
class Inner//在方法中,相當(dāng)于局部成員,不能為static或private
{
void fun()//不能定義靜態(tài)成員(變量和方法)
{
System.out.println("訪問(wèn)外部類成員變量:+ Outer.this :" + Outer.this.x);
System.out.println("局部?jī)?nèi)部類訪問(wèn)本地變量定義為final:" + y);
System.out.println("方法中的參數(shù)需定義為final:" + a);
}
}
new Inner().fun();
}
}
class InnerClassDemo0
{
public static void main(String[] args)
{
Outer ou = new Outer();
ou.method(7);//打印3、4、7
ou.method(8);//打印3、4、8
}
}
- 說(shuō)明:
在method
方法中聲明了Inner
的內(nèi)部類,同時(shí)也產(chǎn)生了Inner
的內(nèi)部類實(shí)例化對(duì)象,并調(diào)用其內(nèi)部的方法。
method
方法參數(shù)a
必須定義為final
,在傳入7后,運(yùn)行method
方法結(jié)束后,在棧內(nèi)存中局部變量a
就會(huì)隨即消亡,然后就可以再傳入8,運(yùn)行下一個(gè)method方法。
5、匿名內(nèi)部類:
1、匿名內(nèi)部類:就是內(nèi)部類的一種簡(jiǎn)寫格式。
當(dāng)只創(chuàng)建該類的一個(gè)對(duì)象,可不用再為其命名。所以稱之為匿名內(nèi)部類。
代碼示例:
class Outer2
{
int x = 3;
public void fun()
{
/*
其中Inner()被改寫為AbsDemo(){} (其實(shí)就是對(duì)父類的復(fù)寫)
*/
new AbsDemo()//看這里
{
void show()
{
System.out.println("匿名show:" + x);
}
}.show();
}
}
2、定義前提:
內(nèi)部類必須繼承一個(gè)類或?qū)崿F(xiàn)接口。
但是有一種很特殊,可以不直接繼承一個(gè)父類,仍可定義一個(gè)匿名內(nèi)部類。因?yàn)槿魏晤惗际荗bject的子類。
如:
new Object()
{
類中的內(nèi)容
fun()方法
}.fun();
3、格式:
new 父類或接口(參數(shù)){定義子類的內(nèi)容};
4、要點(diǎn)說(shuō)明:
A.其實(shí)匿名內(nèi)部類就是一個(gè)匿名子類對(duì)象,可以理解為帶有內(nèi)容的對(duì)象。
B.匿名內(nèi)部類中的方法最好少于3個(gè),方法少,比較方便簡(jiǎn)單,匿名內(nèi)部類一定要簡(jiǎn)化,否則就違背了初衷。
6、靜態(tài)內(nèi)部類
1、概述:
上面提到當(dāng)內(nèi)部類在成員變量的位置上,可被成員修飾符static修飾,這就是靜態(tài)內(nèi)部類
2、使用前提:
某些情況下,會(huì)把內(nèi)部類作為一個(gè)隱藏的類,不需要使用內(nèi)部類引用外部類的對(duì)象。因此,可以將外部類聲明為static,就可以消除產(chǎn)生的引用。在內(nèi)部類不需要訪問(wèn)外部類對(duì)象的時(shí)候,應(yīng)該使用靜態(tài)內(nèi)部類。
下面是示例:
/*
靜態(tài)內(nèi)部類測(cè)試:最大值最小值
*/
class ArrayAlg
{
public static class Pair
{
private double first;
private double second;
//構(gòu)造函數(shù)獲得兩個(gè)值
public Pair(double first,double second)
{
this.first = first;
this.second = second;
}
//訪問(wèn)器:訪問(wèn)私有變量first和second
public double getFirst()
{
return first;
}
public double getSecond()
{
return second;
}
}
//定義一個(gè)獲得最大值和最小值的功能
public static Pair minmax(double[] arr)
{
//min和max要分別設(shè)置最大和最小,然后才能和數(shù)組中的數(shù)比較
double min = Double.MAX_VALUE;
double max = Double.MIN_VALUE;
for (int i=0;i<arr.length;i++)
{
if (min > arr[i])
min = arr[i];
if (max < arr[i])
max = arr[i];
}
return new Pair(min,max);
}
}
class ArrayZDemo
{
public static void main(String[] args)
{
double[] d = new double[20];
for (int i=0;i<d.length;i++)
d[i] = 100*Math.random();
ArrayAlg.Pair p = ArrayAlg.minmax(d);
System.out.println("min = " + p.getFirst());
System.out.println("max = " + p.getSecond());
}
}
練習(xí):
interface Inter
{
void method();
}
class Test
{
//補(bǔ)足代碼,用匿名內(nèi)部類
}
class NInnerClassTest
{
public static void main(String[] args)
{
Test.function().method();
}
}
對(duì)于Test.function().method();的理解:
Test.function():類中有一個(gè)靜態(tài)的方法function。
method():function這個(gè)方法運(yùn)算后的結(jié)果是一個(gè)對(duì)象,而且是一個(gè)Inter類型的對(duì)象。
--->因?yàn)橹挥惺荌nter類型的對(duì)象,才可以調(diào)用method方法。
結(jié)果:
interface Inter
{
void method();
}
class Test
{
public static Inter function()
{
return new Inter()
{
public void method()
{
System.out.println("使用靜態(tài)");
}
};
}
}
//測(cè)試結(jié)果
class NInnerClassTest
{
public static void main(String[] args)
{
Test.function().method();
}
}
匿名內(nèi)部類的應(yīng)用:
class NInnerClassTest
{
public static void main(String[] args)
{
show(new Inter()
{
public void method()
{
System.out.println("method show run");
}
}
public static void show(Inter a)
{
a.method();
}
}
三、多態(tài)
多態(tài):可理解為事物存在的多種體現(xiàn)形態(tài)。又稱為動(dòng)態(tài)綁定,是java的核心機(jī)制之一。
理解:多態(tài)是在運(yùn)行期間,判斷引用實(shí)際類型,根據(jù)實(shí)際類型調(diào)用相應(yīng)的方法。
比如說(shuō)人又男女之分,動(dòng)物有貓、狗等之分
1、多態(tài)的體現(xiàn)形式:
1、父類的引用指向了自己子類的對(duì)象。
2、父類的引用可接收子類的對(duì)象。
比如說(shuō)Person p = new Student();
中p指向了Student中的一個(gè)對(duì)象。
如圖:
2、多態(tài)的前提:
1、必須是類與類之間的關(guān)系,如繼承和實(shí)現(xiàn)關(guān)系
2、要存在覆蓋的操作,父類中必須由方法被子類覆蓋,即重寫
3、有父類引用指向子類對(duì)象
3、多態(tài)的利弊:
1、好處:大大提高了程序的擴(kuò)展性
2、弊端:雖然提高擴(kuò)展性,但是只能使用父類的引用訪問(wèn)父類中的成員,不可預(yù)先使用子類。這是由于,子類在父類之后加載,此時(shí)還沒(méi)有子類被加載。
在下面的代碼中,Animal a = new Cat();是一種“類型提升,向上轉(zhuǎn)型”的過(guò)程。如果要實(shí)現(xiàn)Cat中的其他Animal沒(méi)有的功能,那么就需要強(qiáng)制將父類的引用轉(zhuǎn)換成子類類型,然后再調(diào)用子類的方法:
Cat c = (Cat) a;
c.catchM();
注意:
1、一定不能將父類的對(duì)象轉(zhuǎn)換成子類類型。
2、可轉(zhuǎn)換的:父類引用指向自己子類的對(duì)象時(shí),該引用可被提升,也可被強(qiáng)制轉(zhuǎn)化。
3、多態(tài)自始至終均為子類對(duì)象在做變化。
例如:
/**
分析:
1、定義一個(gè)動(dòng)物類這個(gè)超類類型(抽象),含有一個(gè)吃飯的抽象方法
2、定義子類(如貓,狗等),含有自己的方法(貓:抓老鼠;狗:看家)
3、用多態(tài)實(shí)現(xiàn)子類方法
*/
abstract class Animal //抽象類
{
abstract void eat();
}
class Cat extends Animal //Cat繼承父類Animal
{
//復(fù)寫父類的抽象方法
void eat(){
System.out.println("吃魚(yú)");
}
//定義自身功能
void catchM(){
System.out.println("抓老鼠");
}
}
class Dog extends Animal
{
//復(fù)寫父類的抽象方法
void eat(){
System.out.println("啃骨頭");
}
//定義自身功能
void kanJ(){
System.out.println("看家");
}
}
class DuoTaiTest
{
public static void main(String[] args)
{
Animal a1 = new Cat();//多態(tài)運(yùn)用a2.eat();
Dosome(a1);
Cat c = (Cat)a1;
Dosome(c);
c.catchM();
Animal a2 = new Dog();
a2.eat();
Dosome(a2);
Dog d = (Dog)a2;
Dosome(d);
d.kanJ();
}
public static void Dosome(Animal a)
{
a.eat();
}
}
4、多態(tài)的特點(diǎn):
1、在多態(tài)中成員函數(shù)的特點(diǎn):
·編譯時(shí)期:參閱引用型變量所屬的類中,是否有調(diào)用的方法,如果有,則編譯通過(guò),若沒(méi)有,則編譯失敗。如上面的代碼中,引用型變量a是父類Animal的類型,其中有eat 的方法,所以沒(méi)問(wèn)題,但是如果調(diào)用a.catchM()
就會(huì)編譯失敗。
·運(yùn)行時(shí)期:參與對(duì)象所屬的類中,是否有調(diào)用的方法。如引用型變量c是所屬于Cat類型的,可以調(diào)用c.catchM()
總結(jié):成員函數(shù)在多態(tài)調(diào)用時(shí),編譯看左邊,運(yùn)行看右邊。子類中局部有變量就訪問(wèn)局部的,沒(méi)有就訪問(wèn)成員的變量,成員中沒(méi)有的就在父類中找;如果父類中沒(méi)有,編譯失敗。
2、在多態(tài)中成員變量(和靜態(tài)成員)的特點(diǎn):
·無(wú)論編譯和運(yùn)行,都參考左邊的,即引用型變量所屬的類型。也就是說(shuō)父類中有自己的變量,則先找父類自己的成員。
·非靜態(tài)有重寫的特點(diǎn),靜態(tài)一般不被重寫。
原因:因?yàn)楫?dāng)調(diào)用靜態(tài)方法時(shí),只要建立子類對(duì)象,父類與子類中的靜態(tài)方法都會(huì)隨之加載入內(nèi)存,是不需要調(diào)用就可直接用類名.方法名的,而不需要對(duì)象。只要引用還存在,就看引用變量的類型。
class Father
{
int num = 3;
void method1()
{
System.out.println("father-1");
}
void method2()
{
System.out.println("father-2");
}
static void method4()
{
System.out.println("father-4");
}
}
class Son extends Father
{
int num = 5;
void method1()
{
System.out.println("son-1");
}
void method3()
{
System.out.println("son-3");
}
static void method4()
{
System.out.println("son-4");
}
}
class DuotaiYYDemo
{
public static void main(String[] args)
{
Father f = new Son();
Son s = new Son();
f.method1();//son-1
s.method1();//son-1
f.method2();//father-2
s.method3();//son-3
//f.method3();報(bào)錯(cuò)
f.method4();//father-4
s.method4();//son-4
System.out.println(f.num);//3
System.out.println(s.num);//5
}
}
注:
如果在每次調(diào)用方法時(shí)都要進(jìn)行搜索的話,效率是非常低的。因此,JVM虛擬機(jī)會(huì)預(yù)先為每個(gè)類在方法區(qū)創(chuàng)建一個(gè)方法表,列出了所有方法的參數(shù)和實(shí)際調(diào)用的方法。因此,在真正調(diào)用的時(shí)候,虛擬機(jī)只查找這個(gè)方法表就可行了。而且,方法區(qū)中會(huì)有靜態(tài)方法區(qū)和非靜態(tài)方法區(qū)之分(如圖)。其中像this和super這兩個(gè)關(guān)鍵字存在于非靜態(tài)方法區(qū)中,而被static修飾的,存在于靜態(tài)方法區(qū)中。
5、多態(tài)的應(yīng)用
1、定義好工具類,即將共同行為封裝在一個(gè)類中。
2、對(duì)類型進(jìn)行抽取,---->多態(tài)的產(chǎn)生。
3、操作同一個(gè)大類型,對(duì)其中的小類型均可操作
四、包
1、包概述:
java中的包就相當(dāng)于系統(tǒng)中的文件夾。
當(dāng)我們需要將各個(gè)類分門別類的存放的時(shí)候,或者含有不同功能的相同類名的時(shí)候,需要用到包(package)。包可以將相關(guān)的類放在一起,并可以將兩個(gè)或多個(gè)相同文件名的文件放在不同包中。
2、包的作用:
1、為避免多個(gè)類重名的情況,如果出現(xiàn)兩個(gè)相同名字的類,可通過(guò)包將兩者區(qū)分,從而避免沖突
2、對(duì)類文件進(jìn)行分類管理,可以將相關(guān)的一些類放在同一個(gè)包中。
3、給類提供多層命名空間,如a包中的Demo.class文件即packagea.Demo.class
3、規(guī)則:
1、寫在程序的第一行,因?yàn)槭前碌念悾扔邪耍拍軐㈩惙胚M(jìn)去。
2、類名的全稱:包名.類名
3、包是一種封裝形式,是java封裝性的體現(xiàn)。
4、包與包之間的訪問(wèn):
1、要訪問(wèn)其他包中的類,需要定義類名的全名:包名.類名
2、如果包不再當(dāng)前目錄下,需要設(shè)置classpath,告知虛擬機(jī)包的執(zhí)行路徑
3、有了包,范圍變大,一個(gè)包中的類要被訪問(wèn),必須有足夠大的權(quán)限。
注:
a.包與包間進(jìn)行訪問(wèn),被訪問(wèn)的包中的類以及類中的成員,需要public修飾。
b.不同包中的子類還可直接訪問(wèn)父類中被protected權(quán)限修飾的成員。包與包間可使用的權(quán)限有兩種:public和protected。
c.其中protected只用于覆蓋。
示例:
package cn.conpany.test;
public class FatherDemo {
//父類受保護(hù)方法
protected void show(){
System.out.println("protected father");
}
//父類公有方法
public void fuc(){
System.out.println("public father");
}
}
package cn.conpany.test.array;
public class SonDemo extends cn.conpany.test.FatherDemo{
public void showSon(){
//自定義方法
System.out.println("son show");
//調(diào)用父類方法
show();
}
}
package cn.conpany.test.object;
import cn.conpany.test.FatherDemo;
import cn.conpany.test.array.SonDemo;
public class PackageDemo {
public static void main(String[] args) {
//創(chuàng)建子父類對(duì)象
FatherDemo f = new FatherDemo();
SonDemo s = new SonDemo();
//類PackageDemo可訪問(wèn)其他類公有方法
f.fuc();//public father
//訪問(wèn)其他類受保護(hù)方法,不可
//f.show();//報(bào)錯(cuò)
s.fuc();//public father
//子類可訪問(wèn)父類受保護(hù)方法
s.showSon();/*son show
protected father*/
}
}
5、包的導(dǎo)入:
1、為了簡(jiǎn)化類名的書(shū)寫,使用import導(dǎo)入
如:import packa.packb.packc.*; 是將包packa下的包packb下的包packc下的所有類導(dǎo)入進(jìn)來(lái)。
注:如果需要packb下還有類需要導(dǎo)入,則還需在導(dǎo)入,
如: import packa.packb.*;
2、注意事項(xiàng):
a.兩個(gè)包中有相同類名文件,當(dāng)再統(tǒng)一類中創(chuàng)建對(duì)象時(shí),需要加上包名.類名創(chuàng)建。
b.建議定義包名不要重復(fù),可以使用URL來(lái)定義,因?yàn)閁RL是唯一的。
如:
www.itcast.com---->package cn.itcast.Demo以及cn.itcast.Test
Java中各個(gè)主要包的作用(javax開(kāi)頭的都是擴(kuò)展包)
java.util是JAVA的utility工具包,包含一些使用工具類,如定義系統(tǒng)特性、使用與日期日歷相關(guān)的函數(shù)等的類
java.lang是JAVA的language核心語(yǔ)言包;如String、Math、Integer、System、Thread,提供常用的功能。特殊之處是不需要導(dǎo)入,是作為默認(rèn)導(dǎo)入的包。
java.awt是JAVA的abstractwindow toolkit,抽象窗口工具包;包含了構(gòu)成抽象窗口共具體的多個(gè)類,這些類用于構(gòu)建和管理應(yīng)用程序的圖形用戶(GUI)。
java.applet是創(chuàng)建APPLET的必須包;包含applet運(yùn)行時(shí)所需要的一些類。
java.net是JAVA有關(guān)網(wǎng)絡(luò)操作的包。
java.io是JAVA的輸入輸出流的包。
java.sql是JAVA的數(shù)據(jù)庫(kù)操作包。
javax.swing是新的界面包。