面向對象思想的主要體現:
面向對象:將功能封裝進對象,強調具備了功能的對象。
面向對象的特點:
1、是一種符合人們思考習慣的思想
2、可以將複雜的事情簡單化
3、將程序員從執行者轉換成了指揮者
4、完成需求時:先要去找具有所需的功能的對象來用。如果該對象不存在,那麼創建一個具有所需功能的對象。這樣簡化開發並提高複用。
開發的過程:其實就是不斷的創建對象,使用對象,指揮對象做事情。
設計的過程:其實就是在管理和維護對象之間的關係。
java中描述事物通過類的形式體現,類是具體事物的抽象,概念上的定義。對象即是該類事物實實在在存在的個體。
成員變量:成員變量定義在類中,在整個類中都可以被訪問。成員變量隨着對象的建立而建立,存在於對象所在的堆內存中。成員變量有默認初始化值。
局部變量:局部變量只定義在局部範圍內,如:函數內,語句內等。局部變量存在於棧內存中。作用的範圍結束,變量空間會自動釋放。局部變量沒有默認初始化值。
主函數的定義:
Public:代表着該函數的訪問權限是最大的。
Static:代表主函數隨着類的加載就已經存在了。
Void:主函數沒有具體的返回值。
Main:不是關鍵字,但是是一個特殊的單詞,可以被jvm識別。
(string[] ags):函數的參數,參數類型是一個數組,該數組中的元素是字符串。字符串類型的數組。
主函數是固定格式的:jvm識別。
Jvm在調用主函數時,傳入的是now string[0];
匿名對象使用方式一:當對對象的方法只調用一次時,可以用匿名對象來完成,這樣寫比較簡化。(如果對一個對象進行多個成員調用,必須給這個對象起個名字。)
匿名對象使用方式二:可以將匿名對象作爲實際參數進行傳遞。
封裝:是指隱藏對象的屬性和實現細節,僅對外提供公共訪問方式。
封裝好處:
1、將變化隔離。
2、便於使用。
3、提高重用性。
4、提高安全性。
封裝原則:將不需要對外提供的內容都隱藏起來。把屬性都隱藏,提供公共方法對其訪問。
private關鍵字:是一個權限修飾符。用於修飾成員(成員變量和成員函數),被私有化的成員只在本類中有效。
常用之一:將成員變量私有化,對外提供對應的set ,get方法對其進行訪問。提高對數據訪問的安全
面向對象(靜態什麼時候使用)
要從兩方面下手:
因爲靜態修飾的內容有成員變量和函數。
什麼時候定義靜態變量(類變量)呢?
當對象中出現共享數據時,該數據被靜態所修飾。
對象中的特有數據要定義成非靜態存在於堆內存中。
什麼時候定義靜態函數呢?當功能(函數)內部沒有訪問到非靜態數據(對象的特有數據),那麼該功能可以定義成靜態的。
面向對象(靜態的應用-工具類)
靜態的應用
每一個應用程序中都有共性的功能,
可以將這些功能進行抽取,獨立封裝。(靜態)以便複用。
雖然可以通過建立Arraytool的對象使用這些工具方法,對數組進行操作。發現了問題:
1,對象是用於封裝數據的,可是ArrayTool對象並未封裝特有數據。
2,操作數組的每一個方法都沒有用到ArrayTool對象中的特有數據。
這時就考慮,讓程序更嚴謹,是不需要對象的。
可以將ArrayTool中的方法都定義成static的。直接通過類名調用即可。
將方法都靜態後,可以方便於使用,但是該類還是可以被其他程序建立對象的。
爲了更嚴謹,強制讓該類不能建立對象。
可以通過將構造函數私有化完成。
還有些方法只對內起作用,不對外起作用,也可將此方法私有化。
面向對象(幫助文檔的製作javadoc)
set classpath=.;c:\myclass(.;代表當前文件夾,作用是文件不在同一個文件夾使用。)
類需要有public修飾才能被說明爲幫助文檔。
一個類中默認會有一個空參數的構造函數。
這個默認的構造函數的權限和所屬類一致。
這個類被public修飾,那麼默認的構造函數,也有public修飾。
如果構造函數被定義,就無默認構造函數。
面向對象(靜態代碼塊)
格式:
Static
{
靜態代碼塊中的執行語句。
}
特點:隨着類的加載而執行,只執行一次(再次建立不執行),並優先於主函數運行。構造代碼塊的優先級比構造函數高。
面向對象(對象的初始化過程)
構造代碼塊的優先級比構造函數高。
先是默認初始化,然後是顯示初始化,緊跟是構造代碼塊初始化,接下來是構造函數初始化。
person p=new person("zhangsan",20);
該句話都做了什麼事?
1,因爲new用到了person.class.所以會先找到person.class。
2,執行該類中的static代碼塊,如果有的話,給person.class類進行初始化。
3,在堆內存中開闢空間,分配內存地址。
4,在堆內存中建立對象的特有屬性。並進行默認初始化。
5,對特有屬性進行顯示初始化。
6,對對象進行構造代碼塊初始化。
7,對對象進行對應的構造函數初始化。
8,將內存地址付給棧內存中的P不變量。
9,因爲不涉及靜態方法調用,所以靜態方法沒有初始化。(靜態方法只在調用是初始化)
面向對象(單例設計模式)
設計模式:(解決問題最行之有效的方法。完全偏思想,不僅JAVA可以用。)
JAVA中有23種設計模式:其中一種:單例設計模式:解決一個類在內存中只存在一個對象。(要保證對象在內存中的唯一性)
想要保證對象唯一:
1,爲了避免其它程序過多建立該對象。先禁止其它程序建立該對象。
2,還爲了其他程序程序可以訪問到該對象,只好在本類中,自定義一個對象。
3,爲了方便其他程序對自定義對象的訪問,可以對外提供一些訪問方式。
這三步怎麼用代碼體現呢?
1,將構造函數私有化。
2,在類中創建一個本類對象。
3,提供一個方法可以獲取到該對象。
對於事物該怎麼描述,還怎麼描述。
當需要將該事物的對象保證在內存中唯一時,就將以上的三步加上即可。
面向對象(繼承-概述)
類本身就是一種抽象。
多個類中存在相同屬性和行爲時,將這些內容抽取到單獨一個類中,那麼多個類無需再定義這些屬性和行 爲,只要繼承單獨的那個類即可。多個類可以稱爲子類,單獨這個類稱爲父類或者超類。子類可以直接訪問父類中的非私有的屬性和行爲。通過extends 關鍵字讓類與類之間產生繼承關係。class SubDemo extends Demo{}
被繼承的爲父類,提高代碼的複用性,繼承讓類與類之間產生關係,有了這個關係,纔有了多態的特性。
注意:
1、千萬不要爲了獲取其它類的功能,簡化代碼而繼承。
2、類與類之間要有所屬( " is a " )關係,xx1是xx2的一種。
如果父類中有的功能不是子類應該具備的,就不是繼承。
JAVA語言中:只支持單繼承,不支持多繼承。
因爲多繼承容易帶來安全隱患:因爲當多個父親中定義了相同功能,當功能內容不同時,子類對象不確定要運行哪一個。
但是JAVA保留這種機制,並用另一種體現形式來完成表示。多層實現。
Java支持多層繼承,也就是一個繼承體系。
如何使用一個繼承體系中的功能呢?
想要使用體系,先查閱體系父親的描述,因爲父類中定義的是該體系中共性功能。
通過了解共性功能,就可以知道該體系的基本功能。
那麼這個體系已經可以基本使用了。
那麼在具體調用時,要創建子類的對象,爲什麼呢?
一、是因爲有可能父類不能創建對象。
二、是創建子類對象可以使用更多的功能,包括基本的也包括特有的。
簡單一句話:查閱父類功能,創建子類對象使用功能。(一個孩子只能有一個父親)
面向對象(聚集關係)
聚合(聚集):指的是整體與部分的關係。通常在定義一個整體類後,再去分析這個整體類的組成結構。從而找出一些組成類,該整體類和組成類之間就形成了聚合關係。
組合:也表示類之間整體和部分的關係,但是組合關係中部分和整體具有統一的生存期。一旦整體對象不存在,部分對象也將不存在。部分對象與整體對象之間具有共生死的關係。
聚合和組合的區別在於:
聚合關係是“has-a”關係,組合關係是“contains-a”關係;
聚合關係表示整體與部分的關係比較弱,而組合比較強;
聚合關係中代表部分事物的對象與代表聚合事物的對象的生存期無關,一旦刪除了聚合對象不一定就刪除了代表部分事物的對象。組合中一旦刪除了組合對象,同時也就刪除了代表部分事物的對象。
聚合∶分散的聚集到一起。
組合:幾個獨立部分組成的整體,事物的聯繫關係更緊密。(按照事物的緊密程度進行單獨的劃分)
面向對象(子父類中變量的特點)
子父類出現後,類成員的特點:
類中成員:
1.變量。
2,函數。
3,構造函數。
1,變量
如果子類中出現非私有的同名成員變量時,
子類要訪問本類中的變量,用this
子類要訪問父類中的同名變量,用super。
super 的使用和this的使用幾乎一致。
this代表的是本類對象的引用。
面向對象(子父類中函數的特點-覆蓋)
修改源碼絕對是災難。
子父類中的函數。
當子類出現和父類一模一樣的函數時。
當子類對象調用該函數,會運行子類函數的內容。
如同父類的函數被覆蓋一樣。
這種情況是函數的另一個特性:重寫(覆蓋)
當子類繼承父類,沿襲了父類的功能,到子類中,
但是子類雖具備該功能,但是功能的內容卻和父類不一致,
這時,沒有必要定義新功能,而是使用覆蓋特殊,保留父類的功能定義,並重寫功能內容。
寫覆蓋注意:
1、子類覆蓋父類,必須保證子類權限大於等於父類權限,纔可以覆蓋,否則編譯失敗。
2、靜態只能覆蓋靜態。
默認(什麼都不寫)權限在public與private之間。
重載:只看同名函數的參數列表。
重寫:子父類方法要一模一樣。
面向對象(子父類中構造函數的特點-子類實例化過程)
子父類中的構造函數。
在對子類對象進行初始化時,父類的構造函數也會運行。那是因爲子類的構造函數裏默認第一行有一條隱式的語句supper();
supper():會訪問父類中空參數的構造函數。而且子類中所有的構造函數裏默認第一行都是super();
爲什麼子類一定要訪問父類中的構造函數?
因爲父類中的數據子類可以直接獲取,所以子類對象在建立時,需要首先看父類是如何對這些數據進行初始化的。
所以子類在對象初始化時,要先訪問一下父類中的構造函數。
如果要訪問父類中指定的構造函數,可以通過手動定義super語句的方式來指定。
注意:super語句一定定義在子類構造函數裏的第一行。
構造函數裏面要麼只能有this語句(都要在第一行)要麼只能有super語句(都要在第一行)
爲什麼都要在第一行:初始化動作要先做。
super()你調用父類的構造方法,爲什麼要調用父類的構造方法呢?那是因爲子類繼承了父類,獲取到了父類中內容(屬性),所以在父類內容之前,要先看父類是如何對自己的內容進行初始化的,所以子類在構造對象時,必須訪問父類中的構造函數,this() 調用子類中其他的構造方法給對象初始化,就是間接的訪問了父類的構造方法this()和super()不能同時出現在一個構造函數裏面,因爲this()必然會調用其它的構造函數,其它的構造函數必然也會有super()語句的存在,所以在同一個構造函數裏面有相同的語句,就失去了語句的意義,編譯器也不會通過。
子類的實例化過程。
結論:子類的所有的構造函數,默認都會訪問父類中空參數的構造函數。
因爲子類每一個構造函數內的第一行都有一句隱式super():
當父類中沒有空參數的構造函數時,子類必須手動通過super語句形式來指定要訪問父類中的構造函數。
當然:子類的構造函數第一行也可以手動指定this語句來訪問本類中的構造函數。
子類中至少會有一個構造函數會訪問父類中的構造函數。
子類實例化過程:
1.分配成員變量的存儲空間並進行默認的初始化,就是用new關鍵字產生對象後,對類中的成員變量按第三章的表3.1中的對應關係對對象中的成員變量進行初始化賦值。
2.綁定構造方法參數,就是new Person(實際參數列表)中所傳遞進的參數賦值給構造方法中的形式參數變量。
3.如有this()調用,則調用相應的重載構造方法(被調用的重載構造方法又從步驟2開始執行這些流程),被調用的重載構造方法的執行流程結束後,回到當前構造方法,當前構造方法直接跳轉到步驟6執行
4.顯式或隱式追溯調用父類的構造方法(一直到Object類爲止,Object是所有Java類的最頂層父類,在本章後面部分有詳細講解),父類的構造方法又從步驟2開始對父類執行這些流程,父類的構造方法的執行流程結束後,回到當前構造方法,當前構造方法繼續往下執行。
5.進行實例變量的顯式初始化操作,也就是執行在定義成員變量時就對其進行賦值的語句,如:
6.執行當前構造方法的方法體中的程序代碼 。
如下實例描述:
class X {
Y b = new Y();//執行Y的構造函數然後返回,接着返回b,執行完X構造方法裏的語句後返回a處,但仍然先初始化成員變量y
X() {//b 先對成員變量顯式初始化,而Y類型的b也算作是成員變量,所以跳到c
System.out.print("X");
}
}
class Y {
Y() {
System.out.print("Y");
}
}
public class Z extends X {
Y y = new Y();
int i=0;
Z() {//a 執行上述描述的1,2步後執行第四步跳到b
System.out.print("Z");
}
public static void main(String[] args) {
new Z();//產生z的實例跳到a
}
}
面向對象(final關鍵字)
final:
1,可以修飾類,函數,變量。
2,被final修飾的類不可以被繼承。爲了避免被繼承,被子類複寫功能。
3,被final修飾的方法不可以被複寫。
4,被final修飾的變量是一個常量只能賦值一次,既可以修飾成員變量,又可以修飾局部變量。
當描述事物時,一些數據的出現值是固定的,那麼這時爲了增強閱讀性,都給這些值起個名字。方便與閱讀,而這個值不需要改變,所以加上final修飾。
作爲常量:常量的書寫規範所有字母都大寫,如果由多個單詞組成。單詞間通過_連接。
面向對象(抽象類)
當多個類中出現相同功能,但是功能主體不同,這時可以進行向上抽取。這時,只抽取功能定義,而不抽取功能主體。這時方法加abstract(抽象),此時這個類也是抽象的,類也用abstract描述。例如:狼和狗共性都是犬科,犬科就是抽象出來的概念。狼和狗都有吼叫的方法,可是吼叫內容是不一樣的。所以抽象出來的犬科雖然有吼叫功能,但是並不明確吼叫的細節。
抽象類特點:
1,抽象方法一定在抽象類中。
2,抽象方法和抽象類都必須被abstract關鍵字修飾。
3,抽象類不可以用new創建對象。因爲抽象方法沒意義。
4,抽象類中的抽象方法要被使用,必須由子類複寫起所有的抽象方法,才能建立子類對象調用。如果子類只覆蓋了部分抽象方法,那麼該子類還是一個抽象類。要想子類不抽象,就必須複寫父類所有的抽象方法。
抽象類和一般類沒有太大不同。該如何描述事物就如何描述事物,只不過該事物出現了一些看不懂的東西。這些不確定的部分,也是該事物的功能,需要明確出現。但是無法定義主體。通過抽象方法來表示。抽象類比一般類多了抽象方法,就是在類中可以定義抽象方法。抽象類不可以實例化。
特殊:抽象類中可以不定義抽象方法,這樣做僅僅是不讓該類建立對象。
面向對象(模版方法設計模式)
需求:獲取一段程序運行的時間。
原理:獲取程序開始和結束的時間並相減即可。
獲取時間:System.currentTimeMillis();
當代碼完成優化後,就可以解決這類問題。
這種方式,模版方法設計模式。
什麼是模版方法呢?在定義功能時,功能的一部分是確定的,但是有一部分是不確定,而確定的部分在使用不確定的部分,那麼這時就將不確定的部分暴露出去。由該類的子類去完成。
面向方法(接口)
接口:初期理解,可以認爲是一個特殊的抽象類 當抽象中的方法都是抽象的,那麼該類可以通過接口的形式來表示。
class用於定義類,interface用於定義接口(imeplements用於接口實現可以實現多實現,extends用於接口繼承可以實現多繼承。)
接口定義時,格式特點:
1,接口中常見定義:常量,抽象方法。
2,接口中的成員都有固定修飾符。
常量固定修飾符:public static final int NUM=3;
方法固定修飾符:public abstract void show();
記住:接口中的成員都是public的。
接口是不可以創建對象的, 因爲有抽象方法。
需要被子類實現,子類對接口中的抽象方法全部覆蓋後,子類纔可以實例化。否則子類是一個抽象類。
接口可以被類多現實,也是對多繼承不支持的轉換形式。Java支持多實現。
一個類在繼承一個類的同時,還可以實現多個接口。
接口與接口之間是繼承關係。類與類之間是繼承關係。類與接口之間是實現關係。extends關鍵詞必須位於implements關鍵詞之前。
接口與接口之間可以支持多繼承。
接口特點:
1,對外暴露規則。
2,提高了功能的擴展性。
3,降低了耦合性。
接口實例:
基本功能定義在類中,擴展功能定義在接口中。
面向對象(多態-概念)
多態:可以理解爲事物存在的多種體現形態。
人:男人,女人。
動物:貓,狗。
貓 x=new 貓();
動物 x=new 貓();
圍繞以下4點學習。
1,多態的體現
父類或者接口的引用指向或者接收自己的子類對象。
2,多態的前提
必須是類與類之間有關係,要麼繼承,要麼實現。
通常還有一個前提:就是存在覆蓋。
3,多態的好處
多態的出現大大提高了程序的擴展性和後期可維護性。
4,多態的弊端:
雖然提高了擴展性,但是隻能使用父類的引用訪問父類中的成員。
5,多態的應用
6,多態的出現代碼中的特點(多態使用的注意事項)
在多態中成員函數(指非靜態,因爲非靜態有重寫特性)的特點:
在編譯時間:對象所屬類參閱引用型變量所屬的類中是否有調用的方法。如果有,編譯通過,如果沒有編譯失敗。
在運行時期:參閱對象所屬的類中是否有調用的方法
簡單總結就是:成員函數在多態調用時,編譯看左邊,運行看右邊。
在多態中成員變量的特點:無論編譯和運行,都參考左邊(引用型變量所屬的類(父類))
在多態中靜態成員函數的特點:無論編譯和運行,都參考左邊。
面向對象(多態-轉型)
如果想調用子類(非父類成員)特用方法(成員)是怎麼調用?
強制將父類的引用,轉成子類類型。向下轉型。
Animal a=new Cat();//類型提升。向上轉型。
Cat c=(cat)a; 類型提升後又被強制轉換。
我們能轉換的是父類應用指向了自己的子類對象時,該應用可以被提升,也可以被強制轉換。
多態自始至終都是子類對象在做着變化。
Animal a=new Animal();
Cat c=(cat)a;這樣操作是錯的,千萬不要出現這樣的操作,就是將父類對象轉成子類類型。
判斷是否屬於這一類用instanceof
if(a instanceof Cat)
{
Cat c=(Cat)a;
c.catchMouse();
}
else if(a instanceof Dog)
{
Dog c=(Dog)a;
c.kanjia();
}
面向對象
Object:是所有對象的直接後者間接父親,傳說中的上帝。
該類中定義的肯定是所有對象都具備的功能。每個類都被extends Object;
Object類中已經提供了對對象是否相同的比較方法。
如果自定義類中也有比較相同的功能,沒有必要重新定義。
只要沿襲父類中的功能,建立自己特有的比較內容即可。這就是覆蓋。
面向對象(內部類訪問規則)
1,內部類可以直接訪問外部類成員,包括私有。之所以可以直接訪問外部類中的成員,是因爲內部類中持有了一個外部類的引用,格式: 外部類名.this
2,要訪問內部類,必須建立內部類對象。
訪問格式:
1,當內部類定義在外部類的成員位置上,而且非私有,可以在外部其他類中直接建立內部類對象。格式:外部類名.內部類 =外部類對象.內部類對象;
Outer.Inner in=new Outer().new Inner();
2,當內部類在成員位置上,就可以被成員修飾符所修飾。
比如,private:將內部類在外部類中進行封裝。
Static:內部類就具備了靜態的特性。
當內部類被static修飾後,只能直接訪問外部類中的static成員。出現了訪問侷限。
在外部其他類中,如何直接訪問static內部類的非靜態成員呢?
new Outer.Inner().function();
在外部其他類中,如何直接訪問static內部類的靜態成員呢?
Outer.Inter.function();
若想在成員內部類中訪問外部類的成員變量,語法爲:OuterClass.this.a;
注意:當內部類中定義了靜態成員,該內部類必須是static的。
凡是被static修飾過的類,方法,變量等,她們都是隨着類的加載而加載,都存放在內存中的方法區裏,優先於對象建立,而非靜態的東西要末存放在堆內存裏(對象等),要末存放在棧內存裏(變量等),他們不在同一塊內存上。
類內部定義的靜態成員,必須沒有實例化就可以載入。
而內部類在沒有靜態修飾時,不能直接被外部類載入,其靜態方法隨之也不能載入。
只有新建一個內部類才能載入其成員,不符合靜態的定義,所以會報錯。
如果內部類定義了靜態成員,則內部類必須是static的。原因同上,當靜態成員隨着類加載而加載時,若內部類不是static的,這時靜態成員已經加載到內存上了,而內部類還沒有建立,靜態成員怎麼能獨立於他所屬的內部類而存在呢?
靜態 就是 沒有實例化 就可以直接用類名去 引用的 成員。如果這個內部類不是靜態的,你在這個類裏面定義了靜態的變量,連這個內部類都不能直接用外部類名去引用,
那你在裏面定義內部變量就沒有意義了。
一句話,內部類都是不確定的,怎麼能確定內部靜態的東西呢?內部類隨着外部對象的建立,都會新產生一個內部類,所以內部類在哪裏產生都不確定的,而且產生之後如果能調用靜態方法,那麼就會在方法區載入很多相同的靜態方法,這樣就與靜態方法矛盾。
當外部類中的靜態方法訪問內部類時,內部類也必須是static的。
靜態方法只能訪問用static修飾的成員。
當描述事物時,事物的內部還有事物,該事物用內部類來描述。
因爲內部事務在使用外部事物的內容。
局部內部類不能定義靜態成員,因爲局部內部類不能被static修飾。
因爲static只能修飾類中的成員,局部內部類跟局部變量一樣,生命週期只存在於局部(即方法的大括號之間),方法執行完就消失,因此不需要修飾符修飾。(如果靜態修飾也沒用,因爲生命週期很短,大括號外面就結束了。)
內部類定義在局部時:
1,不可以被成員修飾符修飾(final可以)
內部類定義在局部時,與局部變量的使用有些類似,局部變量只能被final修飾,而其他的成員修飾符是不能修飾局部變量的。這跟代碼的生命週期有關係,局部變量的生命週期是從定義開始到最後一次被調用,而成員變量的生命週期比局部變量的週期長,因此用來修飾成員變量的修飾符不可以修飾局部變量。同樣的道理,相對於定義在函數外時,內部類定義在內部時,其生命週期比較短,因此也不能被成員修飾符修飾。
2,可以直接訪問外部類中的成員,因爲還持有外部類中的引用。但是不可以訪問它所在的局部中的變量。只能訪問被final修飾的局部變量。
因爲方法中的代碼是由上而下順序執行的,方法運行結束後,局部變量就被銷燬,內部類的生命週期可能會比局部變量的生命週期長;看下面的代碼,方法中的內部類 Inner.class 調用方法中的局部變量 x ,正常調用的時候內部類能夠調用到方法中的局部變量,並將內部類對象 inner 返回,正常調用結束後,如果方法中的局部變量 x 沒有被 final 關鍵字修飾,x 則會被銷燬,我們再通過反射的方式去調用 x 的時候則會發現找不到變量 x ,如果局部變量 x 被 final 關鍵字修飾後,則 x 在方法運行結束後不會被銷燬,而是常駐在內存中直到 JVM 退出,這樣再通過反射調用的時候依然可以找到 x 。
匿名內部類(沒有名字的內部類):
1,匿名內部類其實就是內部類的簡寫格式。
2,定義匿名內部類的前提:
內部類必須是繼承一個類或者實現接口。
3,匿名內部類的格式:new 父親或接口名稱(){定義子類的內容}.fuction()或者父親或接口名稱 新建對象名=new 父親或接口名稱(){定義子類的內容}
4,其實匿名內部類就是一個匿名子類對象。而且這個對象有點胖。可以理解爲帶內容的對象。
5,匿名內部類中定義的方法最好不要超過3個(2個或一個比較好)。
匿名內部類是把建立子類和建立對象封裝爲一體的表現形式。所以匿名對象方法只能調用一次。
匿名對象一般不寫子類特有的成員且不能強轉類型。
什麼時候用匿名類?
當接口中的方法只有1個或2個時,可以用。
沒有父類也沒有接口能使用匿名類嗎?
用上帝之類。Object(所有類的父類)
異常
異常:就是程序在運行時出現不正常情況。
異常由來:問題也是現實生活中的一個具體的事物,也可以通過java的類的形式進行描述。並封裝成對象。(把問題封裝成對象)
其實就是java對不正常情況進行描述後的對象體現。
對於問題的劃分,有2種;一種是嚴重的問題,一種是非嚴重的問題。
對於嚴重的:java通過Error類進行描述。
對於error一般不編寫針對性的代碼對其經行處理。
對於非嚴重的,java通過Exception類進行描述。
對於Exception可以使用針對性的處理方式進行處理。
無論Error或者Exception都具有一些共性內容。(所以可以向上抽取,共有父類Throwable)
比如:不正常情況的信息,引發原因等。
Throwable(Throwable類是java語言中所有錯誤或異常的超類。)
|——Error
|——Exception
異常的處理
Java 提供了特有的語句進行處理。
try
{
需要被檢測的代碼;
}
catch(異常類 變量)
{
處理異常的代碼;(處理方式)
}
Finally
{
一定會執行的語句;
}
對捕獲到的異常對象進行常見方法操作
對象.getMessage() :獲取異常信息,返回對象的詳細信息字符串。//異常信息
對象.toString()返回對象的簡短描述//異常名稱
對象.printStackTrace();//異常名稱,異常信息,異常出現的位置。其實jvm默認的異常處理機制,就是在調用printStackTrace();方法。打印異常的堆棧的跟蹤信息。
throws Exception//在功能上通過throws的關鍵字聲明瞭該功能有可能會出現問題。(拋出可能出現的問題)
對多異常的處理。
1,聲明異常時,建議聲明更爲具體的異常,這樣處理的可以更具體。(聲明多個具體異常就處理多個具體異常)
throws ArithmeticException,ArrayIndexOutofBoundsException聲明瞭2個具體異常(拋出2個異常,可能出現問題的異常。)只要有異常發生,這個程序就已經結束了。(就是要被跳轉)
2,對方聲明幾個異常,就對應有幾個catch塊。
如果多個catch塊中的異常出現繼承關係,父類異常catch塊放在最下面。
建議在進行catch處理時,catch中一定要定義具體處理方式。
不要簡單定義一句e.printStackTrace(),
也不要簡單的就書寫一條輸出語句。
一般是把這些異常用文字記錄下來(bug),做爲每天出現異常記錄下來,然後進行修改。
自定義異常:
因爲項目中會出現特有的問題。
而這些問題並未被java所描述並封裝對象。
所以對於這些特有的問題可以按照java的對問題封裝的思想。
將特有的問題。進行自定義的異常封裝。
自定義異常。
需求:在本程序中,對於除數是負數,也視爲是錯誤的,是無法進行運算的,那麼就需要對這個問題進行自定義的描述。
throw new FushuException();//手動通過throw(與throws的區別,throws拋類,throw拋對象)關鍵字拋出一個自定義異常對象。
當在函數內部出現了throw拋出異常對象,那麼就必須要給對應的處理動作。
要麼在內部try catch處理。
要麼在函數上聲明讓調用者處理。
一般情況,在函數內出現異常,函數上需要聲明。
發現打印的結果中只有異常的名稱,卻沒有異常的信息。
因爲自定義的異常並未定義所屬信息。
如何定義異常信息呢?
因爲父類中已經把異常信息的操作都完成了。
所以子類只要在構造時,將異常信息傳遞給父類通過super語句。
那麼就可以直接通過getMessage方法獲取自定義的異常信息。
自定義異常:
必須是自定義類繼承Exception。
爲什麼要繼承Exception?
異常體系有有一個特點:因爲異常類和異常對象都被拋出。
他們都具備可拋性。這個可拋性是Throwable這個體系中的獨有特點。
只有這個體系中的類和對象纔可以被throws和throw操作。
Throws和throw的區別
1,throws使用在函數上(寫在小括號和大括號之間),throw使用在函數內。
2,throws後面跟的異常類。可以跟多個。用逗號隔開。throw後面跟着是異常對象。
RuntimeException:
Exception中有一個非常特殊的子類異常RuntimeException運行時異常。
如果在函數內拋出拋出該異常,函數上可以不用聲明,編譯一樣通過。
如果在函數上聲明瞭該異常。調用者可以不用進行處理。編譯一樣通過。
之所以不用在函數聲明,是因爲不需要讓調用者處理。當該異常發生時,希望程序終止。因爲在運行時,出現了無法繼續運算的情況,希望停止程序後,程序員對代碼進行修正。
自定義異常時:如果該異常的發生,無法在繼續進行運算,
就讓自定義異常繼承RuntimeException。
對於異常分兩種:
1,編譯時被檢測的異常。(可以處理,繼承Excepttion)
2,編譯時不被檢測的異常(運行時異常。RuntimeException以及其子類,不能處理直接結束,繼承RuntimeException)
老師用電腦上課。這句話怎麼用類描述?用名詞提煉法
開始思考上課中出現的問題。
比如問題是
電腦藍屏。
電腦冒煙。
要對問題進行描述,封裝成對象。
可是當冒煙發生後,出現講課進度無法繼續。
出現了講師的問題:課時計劃無法完成。
finally:
finally代碼塊:定義一定執行的代碼塊。
通常用於關閉資源。
舉例
public void method()
{
連接數據庫;
數據操作;//throw new SQLException();
關閉數據庫;//該動作,無論數據庫操作是否成功,一定要關閉資源。
}
try
{
連接數據庫;
數據操作;//throw new SQLException();
}
catch(SQLException e)
{
}
finally
{
關閉數據庫
}
try ,catch(),finally有三種格式。
第一個格式:(一個try可以對應多個catch)
try
{
}
catch()
{
}
第二個格式:
try
{
}
catch()
{
}
finally
{
}
第三個格式:
try
{
}
finally
{
}
注意:
1,finally中定義的通常是關閉資源代碼。因爲資源必須釋放。
2,finally只有一種情況不會執行,就是當執行到System.exit(0);(這是退出jvm系統的意思。)
只要問題被解決問題可以不用聲明(問題沒有被解決就一定要被聲明),比如
try
{
throw new Exception();
}
catch(Exception e)
{
}
記住一點:catch是用於處理異常。如果沒有catch就代表異常沒有被處理過,如果該異常是檢測時異常。那麼必須聲明(異常如果聲明,聲明在函數上)。
異常在子父類覆蓋中的體現:
1,子類在覆蓋父類時,如果父類的方法拋出異常,那麼子類的覆蓋方法,只能拋出父類的異常或者該異常類的子類。
2,如果父類方法拋出多個異常,那麼子類在覆蓋該方法時,只能拋出父類異常的子集。
3,如果父類或接口的方法中沒有異常拋出,那麼子類在覆蓋方法時,也不可以拋出異常。
如果子類方法發生了異常。就必須要進行try處理。絕對不能拋。
聯習:有一個圓形和長方形。都可以獲取面積。對於面積如果出現非法的數值,視爲是獲取面積出現問題。問題通過異常來表示。
先對這個程序進行基本的設計。
異常總結:
異常是什麼?是對問題的描述。將問題進行對象的封裝。
異常體系:
Throwable
|--Error
|--Exception
|--RuntimeException
異常體系的特點:異常體系中的所有類以及建立的對象都具備可拋性。
也就是說可以被throw和throws關鍵字所操作。
只有異常體系具備這個特點。
throw和throws的用法:
throw定義在函數內,用於拋出異常對象。
throws定義在函數上,用於拋出異常類,可以拋出多個用逗號隔開。
當函數內容有throw拋出異常對象,並未進行try處理。必須要在函數上聲明,否則編譯失敗。(注意:RuntimeException除外,也就是說,函數內如果拋出的是RuntimeException異常,函數上可以不用聲明。)
如果函數聲明瞭異常,調用者需要進行處理,處理方法可以是throws,也可以是try.
異常有兩種:
編譯時被檢測異常
該異常在編譯時,如果沒有處理(沒有拋也沒有try),編譯失敗。
該異常被標識,代表這可以被處理。
運行時異常(編譯時不檢測)
在編譯時,不需要處理,編譯器不檢查。
該異常的發生,建議不處理,讓程序停止。需要對代碼進行修正。
自定義異常:
定義類繼承Exception或者RuntimeException
1,爲了讓該自定義類具備可拋性。
2,讓該類具備操作異常的共性方法。
當要定義自定義異常的信息時,可以使用父類已經定義好的功能。
將異常信息傳遞給父類的構造函數。比如
class MyException extends Exception
{
MyException(String message)
{
super(message);
}
}
自定義異常:是按照java的面向對象思想,將程序中出現的特有問題進行封裝。
異常的好處:
1,將問題進行封裝。
2,將正常流程代碼和問題相分離,方便與閱讀。
異常的處理原則:
1,處理方式有兩種:try或者throws。
2,調用到拋出異常的功能時,拋出幾個,就處理幾個。
一個try對應多個catch。
3,多個catch,父類的catch放到最下面。
4,catch內,需要定義針對性的處理方式,不要簡單的定義printStackTrace,輸出語句。 也不要什麼都不寫。
當捕獲到的異常,本功能處理不了時,可以繼續在catch中拋出。
try
{
throw new AException();
}
catch(AException e)
{
throw e;
}
如果該異常處理不了,但並不屬於該功能出現的異常。
可以將異常轉換後,在拋出和該功能相關的異常。
或者異常可以處理,但需要將異常產生的和本功能相關的問題提供出去,
讓調用者知道。並處理。也可以將捕獲異常處理後,轉換新的異常。
try
{
throw new AException();
}
catch(AException e)
{
//對AException處理。
throw new BException();
}
比如匯款的例子。
異常的注意事項:
在子父類覆蓋時:
1,子類拋出的異常必須是父類的異常的子類或者子集。
2,如果父類或者接口沒有異常拋出時,子類覆蓋出現異常,只能try不能拋。
參閱
ExceptionText.java 老師用電腦上課
ExceptionText1.java 圖形面積。
記住:throw單獨存在時,下面不要定義語句,因爲執行不到。(continue,return,break也是)
包package:
package 必須放在程序的第一行。
一個包中的類要被訪問,必須要有足夠大的權限。所以被訪問的類必須要被public修飾。
類中的成員要被包外訪問,也要公有纔可以被訪問。
總結:包與包之間進行訪問,被訪問的包中的類以及類中的成員,需要被public修飾才能被訪問。
包與包直接的繼承,有一個權限訪問的好處,就是不同包的子類還可以直接訪問父類中被protected權限修飾的成員。
包與包之間可以使用的權限只有兩種,public protected。
public protected default private
同一個類中 ok ok ok ok
同一個包中 ok ok ok
子類 ok ok
不同包中 ok
類加public後,類名必須和java文件保持一致。所以同一個文件,只能一個類被public修飾。
import:爲了簡化類名的書寫,使用的關鍵字,導入的是包中的類。不能導入子包中的類。
c:\myclass\packb\DemoA.class
c:\myclass\packb\haha\Demoz.class
import packb.*;導入DemoA
import pack.haha.*;導入Demoz(不建議用*,用哪個導哪個)
導入不同類時,如果類重名,必須加包名。
建議建立包名不要重複,可以使用url來完成定義,url是唯一的。
package cn.itcast.test(域名不會重複)
jar包(java的壓縮包)
jar -cf haha.jar packa pack