目錄
概念:
核心特性:
類和對象
匿名對象
兩種使用情況
封裝:
概念:
好處:
封裝的原則:
如何實作?
構造函數
特點:
作用:
隐藏機制:
構造函數和一般函數的不同
構造代碼塊:
作用:
特點:
構造代碼塊和構造函數的差別:
this:
Static關鍵字
用法:
被修飾的成員具備以下特點:
注意
靜态代碼塊:
特點:
執行個體變量和類變量的差別:
靜态利弊:
工具類
繼承:
概念:
好處:
知識點:
父子之間有相同的屬性和方法
重寫:
概念:
重寫要求:
調用父類構造函數
為什麼子類一定要通路父類中的構造函數?
final
抽象:
概念:
特點:
接口
基礎知識:
特點:
多态
概念:
多态的展現:
多态的前提:
多态的好處:
多态的弊端:
多态的應用:
在多态中成員函數的特點:
在多态中成員變量的特點:
在多态中,靜态成員函數的特點:
内部類:
概念:
什麼時候用:
通路規則:
通路格式:
内部類定義在局部時
匿名内部類:
概念:
- 面向對象是一種思想
- 是相對于面向過程而言,是基于面向過程的,面向過程強調的是功能行為,面向對象是将功能封裝進對象,強調具備了功能的對象
核心特性:
封裝、繼承,多态
類和對象
類:對現實生活中事物的描述,映射到java中,描述就是class定義的類
對象:就是這類事物,實實在在存在的個體,具體對象就是對應java在堆記憶體中用new建立實體
匿名對象
匿名對象是對象的簡化形式
兩種使用情況
- 當對對象方法僅進行一次調用的時候
- 匿名對象可以作為實際參數進行傳遞
匿名對象有屬性有方法,但是給匿名對象屬性指派沒有意義,運作到;匿名對象就被銷毀了,如
new Person().name=li; //建立對象,賦完值就銷毀了
new Person().age=18; //在此建立對象,在指派,在銷毀,沒有意義
匿名對象作為實際參數傳遞和對象作為實際參數對比
main()
{
Car c=new Car();
show(c); //運作完這一句之後,堆中的實體還是有執行,main中的c指向,是以還不是垃圾,需要等main方法執行完,就成了垃圾,等待回收
show(new Car()); //運作期間不是垃圾,因為有方法中的c所指向,運作完這句代碼,堆中的實體沒有引用,成為了垃圾,等待回收
}
public static void show(Car c)
{
c.num=3;
c.color="red"
c.run();
}
封裝:
概念:
是指隐藏對象的屬性和實作細節,僅對外提供公共通路方式。
好處:
- 将變化隔離
- 便于使用
- 提高重用性
- 提高安全性
封裝的原則:
- 将不需要對外提供的内容都隐藏起來
- 把屬性都隐藏起來,提供公共方法對其通路
如何實作?
我們将屬性隐藏起來,屬性值就不能與外界産生聯系,既要隐藏還要提供公共方法對其通路,于是我們就有了get,set對屬性進行通路控制,而且可以在通路方式中加入邏輯判斷等語句,對通路的資料進行操作,提高代碼健壯性。
代碼邏輯:外界可以通過通路一下方法傳遞參數到類中公共的方法中,進行邏輯判斷後,通過this關鍵字,重新對類中隐藏的屬性指派
構造函數
特點:
- 函數名和類名相同
- 不用定義傳回值類型
- 不可以寫return語句
- 可以重載
作用:
給對象進行初始化,對象一建立就會調用與之對應的構造函數
隐藏機制:
當一個類中沒有定義構造函數時,那麼系統會預設給類加入一個空參數的構造函數,這個預設的構造函數的權限和所屬類一緻,如果類被public修飾,那麼預設的構造函數也帶public修飾符,如果類沒有被public修飾,那麼預設的構造函數,也沒有pubilc修飾,預設構造函數的權限是随着類的變化而變化的
當在類中自定義了構造函數後,預設的構造函數就沒有了
構造函數和一般函數的不同
- 構造函數是在對象一建立就運作,給對象初始化
- 而一般函數是對象調用才執行,是給對象添加對象具備的功能
- 一個對象建立,構造函數隻運作一次
- 而一般方法可以被該對象調用多次
構造代碼塊:
作用:
給對象進行初始化
特點:
- 對象一建立就運作,而且優先于構造函數執行
- 構造代碼塊中定義的是不同對象共性的初始化内容
構造代碼塊和構造函數的差別:
構造代碼塊是給所有對象進行統一初始化,而構造函數是給對應的對象初始化,因為對象的名字都不一樣,是以構造函數具有唯一性,但是構造代碼塊沒有名字,是以會所有的對象初始化
this:
- 代表本類的對象,代表它所在函數所屬對象的引用,簡單說:哪個對象在調用this所在的函數,this就代表哪個對象
- 可以區分局部變量和成員變量同名的情況
- 可以用于構造函數之前進行互相調用,這樣的情況隻能定義在構造函數的第一行,因為初始化要先執行
class Person
{
Person()
{
this("li")
}
Person(String name)
{
this();
this.name=name;
}
}
Static關鍵字
用法:
用于修飾成員(成員變量和成員函數)
被修飾的成員具備以下特點:
- 随着類的加載而加載:靜态會随着類的消失而消失,生命周期長
- 優先于對象的存在:靜态是存在,對象是後存在
- 被所有對象所共享
- 可以直接被類名調用,也可以被對象調用
注意
- 靜态方法隻能通路靜态成員:非靜态方法既可以通路靜态也可以通路非靜态,因為非靜态方法的建立,說明靜态成員已經建立了,但是靜态方法的建立,可能對象還沒有建立,非靜态方法也就不可能建立
- 靜态方法中不可以寫this,super關鍵字:因為靜态優先于對象存在,是以靜态方法中不可以出現this
- 主函數是靜态的
靜态代碼塊:
static
{
靜态代碼塊中的執行語句
}
特點:
随着類的加載而執行,隻執行一次(不管在new幾個對象,都隻執行一次),并優先于主函數,用于給類進行初始化
Person p =new Person("張三",20);
/*
這句話做了什麼事情?
1.因為new用到了Person.class,是以會先找到Person.class檔案并加載到記憶體中
2.執行該類中static代碼塊,如果有的話,給Person.class類進行初始化
3.在堆記憶體中開辟空間,配置設定記憶體位址
4.在堆記憶體中建立對象的特有屬性,并進行預設初始化
5.對屬性進行顯示初始化,如:private String name="li";成員變量
6.對對象進行構造代碼塊初始化
7.對對象進行對應的構造函數初始化
8.将記憶體位址賦給棧記憶體中的p變量
*/
靜态代碼塊:有些代碼必須在項目啟動的時候就執行,這種代碼是主動執行的(當類被載入時,靜态代碼塊被執行,且隻被執行一次,靜态塊常用來執行類屬性的初始化)
靜态方法:需要在項目啟動的時候就初始化,在不建立對象的情況下,這種代碼是被動執行的(靜态方法在類加載的時候就已經加載 可以用類名直接調用)。
兩者的差別是:靜态代碼塊是自動執行的,
靜态方法是被調用的時候才執行的.
靜态代碼塊,在虛拟機加載類的時候就會加載執行,而且隻執行一次;
非靜态代碼塊,在建立對象的時候(即new一個對象的時候)執行,每次建立對象都會執行一次
不建立類執行靜态方法并不會導緻靜态代碼塊或非靜态代碼塊的執行
靜态代碼塊和靜态變量執行按照先後順序執行(自動執行),靜态方法時被調用的時候才執行,但是已經被初始化了
轉存失敗重新上傳取消
正在上傳…重新上傳取消
執行個體變量和類變量的差別:
1.存放位置
- 類變量随着類的加載而存在于方法區中
- 執行個體變量随着對象的建立而存在堆記憶體中
2.聲明周期
- 類變量聲明周期最長,随着類的消失而消失
- 執行個體變量聲明周期随着對象的消失而消失
靜态利弊:
利處:對對象的共享資料進行單獨空間的存儲,節約空間,沒有必要每一個對象都存儲一份
弊端:聲明周期過長,通路出現局限性(靜态隻能通路靜态)
工具類
每一個應用程式中都有共性的功能,可以将這些功能進行抽取,獨立封裝以便複用(封裝)
當我們發現對象是用于封裝資料的,但是我們的工具類中的對象并未封裝特有資料,而且操作我們工具類對象的也沒有用到我們裡面特有的資料,這就要考慮讓程式更加嚴謹,是不需要對象的,可以将類中的方法定義為static,直接通過類名調用(靜态類)
将方法都靜态後,可以友善于使用,但是該類還是可以被其他程式建立對象的(還是可以new的),為了更為嚴謹,強制讓該類不能建立對象,可以通過構造函數私有化完成(外界不可以new了,隻能類名.方法名)
我們寫好工具類之後,需要釋出給其他人使用需要有一個手冊,通過在代碼中的特殊辨別,可以用javadoc自動生成幫助文檔
/**
@param arr 接受一個int類型的數組
@param a 要置換的位置
...
、
繼承:
概念:
是一種關系的描述
好處:
提高了代碼的複用性
讓類與類之間産生了關系,有了這個關系,才有了多态的特性
知識點:
java中隻支援單繼承,不支援多繼承
因為多繼承容易帶來安全隐患:當多個父類中定義了相同的功能,當功能内容不同時,子類對象不确定要運作哪一個,但是java保留了這種機制,并用另一種展現形式來完成表示,多實作。
java支援多層繼承。也就是一個繼承體系
如何使用一個繼承體系中的功能呢?
想要使用體系,先查閱體系父類的描述,因為父類中定義的是該體系中的共性功能,通過了解共性功能,就可以知道該體系的基本功能,哪呢這個體系已經可以基本使用了。那麼在具體調用時,要建立最子類的對象,為什麼呢?
一是因為有可能父類不能建立對象
二是建立子類對象可以使用更多的功能,包括基本的也包括特有的
總結:查閱父類功能,建立子類對象使用功能
父子之間有相同的屬性和方法
相同的屬性:通過this(本類對象的引用)和super(父類對象的引用)來區分
相同的方法:通過this和super來區分,也可以通過重寫
子類實作時,子類構造函數中預設在上面加了super(),如果父類沒有無參數的構造函數會報錯
重寫:
概念:
當子類繼承父類,沿襲了父類的功能到子類中,但是子類雖具備該功能,但是功能的内容卻和父類不一緻,這時沒有必要定義新功能,而是使用覆寫,保留父類的功能定義,并重寫功能内容
重寫要求:
1.子類覆寫父類,必須保證子類權限大于等于父類權限,才可以覆寫,否則編譯失敗
2.靜态隻能覆寫靜态
調用父類構造函數
在對子類對象進行初始化時,父類的構造函數也會運作,那是因為子類的構造函數預設第一行有一條隐式的語句 super()
super()會通路父類中空參數的構造函數,而且子類中所有的構造函數預設第一行都是super();
為什麼子類一定要通路父類中的構造函數?
因為父類中的資料子類可以直接擷取,是以子類對象在建立時,需要先檢視父類是如何對這些資料進行初始化的,是以子類在對象初始化時,要先通路一下父類中的構造函數,如果要通路父類中指定的構造函數,可以通過手動定義super語句的方式來指定
注意:
super語句一定要定義在子類構造函數的第一行
當父類中沒有空參數的構造函數時,子類必須手動通過super語句形式來指定要通路父類中的構造函數
當然,子類的構造函數第一行也可以手動指定this語句來通路本類中的構造函數,子類中至少有一個構造函數會通路父類中的構造函數
繼承是對封裝性的一個破壞,為了保證封裝性和繼承,用final來實作
final
- 可以修飾類,方法,變量
- final修飾的類不可以被繼承,為了避免被繼承,被子類重寫功能
- final修飾的方法不可以被重寫
- final修飾的變量是一個常量,隻能被指派一次,既可以修飾成員變量,也可以修飾局部變量
- 内部類隻能通路被final修飾的局部變量
抽象:
概念:
- 當多個類中出現相同的功能,但是功能主體不同,這是可以向上抽取,這時,隻抽取功能定義,而不抽取功能主體。
- 描述事物的時候,該事物出現了一些看不懂的東西,這些不确定的部分,也是該事物的功能,需要明确的出現,但是無法定義主體,就通過抽象方法來表示
特點:
- 抽象方法一定在抽象類中
- 抽象方法和抽象類都必須被abstract關鍵字修飾
- 抽象類不可以用new建立對象,因為調用抽象方法沒有意義,因為裡面都沒有功能主體,也是因為執行個體化沒有意義,如學生類,這個執行個體化沒有意義,但是執行個體化某個學生就有意義了
- 抽象類中的抽象方法要被使用,必須由子類複寫起所有的抽象方法後,建立子類對象調用
繼承實作了基本功能的繼承,但是我想要一些有規則的擴充功能怎麼辦,就用到了接口
接口
基礎知識:
interface{}
接口中的成員修飾符是固定的,接口中的成員都是public的,可以省略不寫,jvm會自動加上
成員常量:public static final
成員函數:public abstract
接口的出現将“多繼承”通過另一種形式展現出來,即“多實作”
接口是不可以建立對象的,因為有抽象方法,需要被子類實作,子類對接口中的抽象方法全部覆寫後,子類才可以執行個體化,否則子類是一個抽象類
接口可以被多實作,那如果出現多個接口中出現同名方法,那不就和多繼承出現一樣的問題麼?
不會出現同樣的問題,因為接口中的方法不會聲明方法體,而多繼承有方法體,接口中的方法可以由子類任意定義
接口可以多繼承,但是不能聲明不同傳回類型的同名方法
特點:
接口是對外暴露的規則
接口是程式的功能擴充
接口可以用來多實作
類與接口之間是實作關系,而且類可以繼承一個類的同時實作多個接口
接口與接口之間可以由繼承關系
多态
概念:
某一類事物的多種存在形态
例如貓這個對象對應的類型是貓類型,同時貓也是動物的一種,也可以把貓稱為動物
動物 y=new 貓();
動物是貓和其他動物中抽取出來的父類型,父類型引用指向了子類對象
多态的展現:
- 父類的引用指向了自己的子類對象
- 父類的引用也可以接收自己的子類對象
多态的前提:
- 必須是類與類之間有關系,要麼繼承,要麼實作,存在覆寫
多态的好處:
- 多态的出現大大的提高程式的擴充性
多态的弊端:
- 提高了擴充性,但是隻能使用父類的引用通路父類中的成員
多态的應用:
public static void main(String[] args)
{
Animal a =new Cat(); //Cat類型提升,向上轉型
a.eat();
//如果想要調用貓的特有方法時,如何操作?
//強制将父類的引用,轉成子類類型,向下轉型
Cat c=(Cat)a;
c.catchMouse();
}
在多态中成員函數的特點:
在編譯期間:參閱引用型變量所屬的類中是否有調用的方法,如果有,編譯通過,如果沒有編譯失敗
在運作期間:參閱對象所屬的類中是否有調用的方法
簡單總結:成員函數在多态調用時,編譯看左邊,運作看右邊
public static void main(String[] args)
{
//Fu中有方法m1,m2,zi中有m3
Fu f=new zi()
f.m1();
f.m2();
f.m3(); //編譯的時候這個會失敗
}
在多态中成員變量的特點:
無論編譯和運作,都參考左邊(引用型變量所屬的類)
因為在堆中生成的對象中會有兩個地方,一個存父類的屬性,一個存子類的屬性,而父類引用指向的是父類的位址,是以擷取的屬性也是父類的屬性
public static void main(String[] args)
{
//Fu中的num為5
Fu f=new zi();
System.out.println(f.num);
//zi中的num為8
zi f=new zi();
System.out.println(f.num);
}
結果:5 8
在多态中,靜态成員函數的特點:
無論編譯和運作,都參考左邊,因為靜态成員是靜态綁定,非靜态成員是動态綁定,有覆寫操作
内部類:
概念:
将一個類定義在另一個類的裡面,對裡面那個類就稱為内部類(内置類,嵌套類)
什麼時候用:
當描述事物時,事物的内部還有事物,該事物用内部類來描述。因為内部事物在使用外部事物的内容
class Body
{
private class XinZang
public void show()
{
new XinZang();
}
}
通路規則:
内部類可以直接通路外部類中的成員,包括私有成員,之是以可以直接通路外部類中的成員,是因為内部類中持有一個外部類的引用,格式:外部類名.this
而外部類要通路内部類中的成員必須要建立内部類的對象
通路格式:
1.當内部類定義在外部類的成員位置上,而且非私有,可以在外部其他類中,可以直接建立内部類對象
格式:
//外部類名.内部類名 變量名=外部類對象.内部類對象;
Outer,Inner in = new Outer().new Inner();
2.當内部類在成員位置上,就可以被成員修飾符所修飾
比如:private:将内部類在外部類中進行封裝
static:内部類就具備static的特性
當内部類被static修飾後,隻能直接通路外部類中的static成員,出現通路局限性
在外部其他類中,如何直接通路static内部類的非靜态成員呢?
new Outer.Inner().function();
在外部其他類,如何通路Static内部類的靜态成員呢?
Outer.Inner.function();
注意:當内部類中定義了靜态成員,該内部類必須是static的
當外部類中的靜态方法通路内部類時,内部類也必須是static的
内部類定義在局部時
1.不可以被成員修飾符修飾
2.可以直接通路外部類中的成員,因為還持有外部類中的引用,但是不可以通路它所在的局部中的變量,隻能通路被final修飾的局部變量
class Outer
{
int x=3;
void method()
{
final int y=4;
class Inner
{
void function()
{
System.out.println(x); //3
System.out.println(y); //4
}
}
}
}
匿名内部類:
1.匿名内部類其實就是内部類的簡寫格式
2.定義匿名内部類的前提
内部類必須是繼承一個類或者實作接口
3.匿名内部類的格式:new 父類或者接口(){定義子類的内容}
4.其實匿名内部類就是一個匿名子類對象。而且這個對象有點胖,可以了解為帶内容的對象
5.匿名内部類中定義的方法最好不要超過3個