:內部類就是在類的內部定義一個類,它的分類有成員內部類、局部內部類、匿名內部類,
它可以定義在類中方法外,也可以定義在類中方法內,內部類的好處是可以訪問外部類的私有成員,但外部類無法訪問內部類的私有成員
通過使用內部類可以確保程序的結構清晰和代碼精煉
編譯後的內部類名稱:InnerTest$A.class
:成員內部類(靜態成員內部類)、局部內部類、匿名內部類
a、成員內部類(非靜態內部類):與外部類的屬性和方法並列,成員內部類可以看作是外部類的實例變量
在內部類中訪問實例變量:this.字段;
在內部類中訪問外部類的實例變量:外部類名.this.字段
成員內部類中不能有靜態字段或方法(final修飾的常量除外),因為Static在加載時就創建,此時內部類可能還沒被實例化
在外部類的外部實例化對象:
Foo foo = new Foo();
Koo koo = foo.new Koo();
Foo.Koo koo = new Foo().new Koo();
b、靜態內部類
靜態內部類可以直接訪問外部類的靜態成員,不能訪問外部類的實例成員,但可以通過外部類的實例(new 對象)來訪問
靜態內部類裡面可以定義靜態成員(其他內部類不可以)
靜態內部類不可以使用private修飾
靜態內部類的對象可以直接生成
Foo.Koo koo = new Foo().new Koo();
c、局部內部類
在方法中定義的內部類稱為局部內部類,類似局部變量,不可以加修飾符public、protected、private,其范圍為定義它的代碼塊
可以訪問外部類的所有成員,還可以訪問所在方法中的final修飾的參數和變量,但不能訪問方法體中的局部變量
d、匿名內部類
匿名內部類沒有類名,它必須繼承一個類或者實現一個接口,並且不能顯示的extends或implements關鍵字
匿名內部類不能有構造方法,因為它沒有類名。可以通過new<父類名>的方法創建實例對象,匿名類的創建與定義同時進行
匿名內部類只能一次性的創建其對象
匿名內部類既可以在方法體中,也可以在參數列表中
注意:匿名內部類一定是在new的後面隱含實現一個接口或繼承一個類,匿名內部類不是抽象類
匿名內部類必須實現他的父類抽象接口或接口裡的所有的抽象方法
new 父類的構造器(實參列表)|實現接口(){
//類體
}
new Object(){
}
:內部類可以直接訪問外部類中的成員,包括私有
最近的外部類要訪問內部類必須建立內部類對象new Inner().fumction()來訪問內部類中的成員
如: Outer.Inner in = new Outer().new Inner();
in.function();
:當描述事物時,事物的內部還有事物,該事物用內部類來描述,因為內部事物在使用外部事物的內容。
內部類定義在局部時,不能使用成員修飾符、static修飾,使用時需要new—
可以直接訪問外部類中的成員,但不可訪問它所在的局部中的變量,只能訪問被final修飾的局部變量
:例1:—-分類
public class Demo2 {
class B{//成員內部類——Demo2B.class
}
staticclassA{//靜態成員內部類——Demo2A.class
}
void show(){
class C{//局部內部類——-Demo21C.class
}
}
publicstaticvoidmain(String[]args){
classC{//局部內部類—-Demo22C.class
}
System.out.println();
}
}
例2:—–匿名內部類
1、 匿名內部類其實就是內部類的簡寫格式
2、 定義前題必須繼承一個類或實現一個接口
3、 匿名內部類的格式: new 父類或接口(){定義子類的內容}
4、 匿名內部類定義的方法最好不要超過三個
public class Test{
public static void main(String[] agrs){
Test t=new Test(); //new了 一個Test對象
t.te(new A(){ //調用實例方法並且聲明一個匿名內部類類作為一個參數傳入
public void as(){
System.out.println(“我是實現了接口A的匿名類”);
}
}
);
}
void te(A a){ //實例方法
a.as();
}
}
interface A{ //聲明了一個接口類
void as(); //抽象方法
}
例3:
class A{
void as(){
System.out.println(“我是內部類A”);
}
}
class B{
void bs(){
System.out.println(“我是內部類B”);
}
}
public class MultipleExtends {
private class C extends A{}
private class D extends B{}
public static void main(String[] args) {
MultipleExtends m=new MultipleExtends(); //聲明一個外部類的對象
MultipleExtends.C c=m.new C(); //讓外部類對象持有一個
MultipleExtends.D d=m.new D();//內部類對象的引用
c.as();
d.bs();
}
}
例4:—–內部類是可以被私有的
public class MemberClass {
private int i=10; //定義一個私有字段
private static int j=20;
public static void main(String[] args) {
MemberClass mc=new MemberClass();//new 一個外部類的對象
A a=mc.new A();//A a=new MemberClass().new A();//new 一個內部類的對象
a.as();//調用內部類的實例方法
}
private class A{
//static int j=6;
//int i=5; //定義一個內部類的實例字段
void as(){ //定義一個內部類的實例方法
System.out.println(“這裡是內部類A”);
System.out.println(“調用外部類私有實例字段i:”+i);
System.out.print(“調用外部類私有靜態字段j:”+j);
}
}
}
//———- java ———-
//這裡是內部類A
//調用外部類私有實例字段i:10
//調用外部類私有靜態字段j:20
例5:—-靜態內部類
public class StaticClass {
private static int i=10; //定義一個私有靜態字段
//private int j=7;
public static void main(String[] args) {
StaticClass sc=new StaticClass();//new 一個外部類的對象
A a=new StaticClass.A(); //new 一個靜態內部類
a.as(); //調用靜態內部類的實例方法
A.at //調用靜態內部類的靜態方法
}
static class A{
int i=5;
static at(){ //定義靜態內部類的靜態方法
System.out.println(“這裡是靜態內部類的靜態方法”);
}
void as(){ //定義靜態內部類的實例方法
System.out.println(“這裡是內部類A”);
System.out.print(“調用外部類私有靜態字段i:”+i);
}
}
}
例6:——局部內部類
public class InteriorClass {
private int i=5;
public static void main(String[] args) {
InteriorClass ic=new InteriorClass(); //new 一個對象
ic.as(); //調用實例方法
// B b=ic.new B();
}
void as(){
final int y=5; //常量
int u=1; //局部變量
class B{
void bs(){
System.out.println(“這裡是內部類B”);
System.out.println(“調用i”+i);
System.out.println(“常量”+y);
}
}
new B().bs();
}
}
i、 異常的含義和分類
a)含義:異常是對問題的描述,將問題進行問題的封裝
b)分類:java.lang.Object—–Throwable(java中所有錯誤和異常的超類)—–Error(無法通過代碼來處理的錯誤)
|—————Exception(可處理的異常,並能恢復運行)
|—RuntimeException(運行時異常)—可以不捕獲也可以不處理
|—-CheckedException(已檢查時異常)—-必須捕獲或處理不然編譯失敗—IOException\SQLException
標簽(Marker)接口:既無字段又無方法—Cloneable/Serializable/EventListener
Error—-如:JVM硬件錯誤—-OutOfMemoryError—內存不足、不斷的創建實例、StackOverflowError—遞歸導致的堆異常
2、異常分類(Throwable)
1、編譯時被檢測的異常
throws 需要處理
2、編譯時不被檢測的異常—運行時異常(RuntimeException或其子類)
函數內throw,函數外不需要聲明,——–無法處理,需要修改代碼
ii、 異常處理
a)RuntimeEception及其子類異常,不需要程序員處理,其後語句不編譯
b)非運行時異常必須處理
c)Exeception中有一個特殊的子類異常RuntimeException,如果在方法內拋出該異常,方法上可以不用聲明,編譯可以通過;如果在方法上聲明了該異常,調用者可以不用處理,編譯可以通過。之所以不在函數聲明,是因為不希望讓使用者處理,當異常發生時,希望程序停止,程序員修正程序代碼
異常的捕獲和處理
第一種格式:
try{
//可能拋出異常的語句
}catch(異常類型 e){
//處理語句1
} catch(異常類型 e){
//處理語句2
}finally{
//一定執行的語句
}
finally只要用於異常處理,修飾異常塊,無論異常是否處理都會執行
finally在return、throw前輸出,不管return是在try還是catch中
finally定義一定執行的代碼,通常用於關閉資源——如:數據庫關閉連接
finally塊在以下情況將不會被執行:
(1)finally塊中發生了異常;
(2)程序所在線程死亡;
(3)在前面的代碼中用了System.exit(0);
(4)關閉CPU。
第二種格式:
try{
}finally{
}
第三種格式:
try{
}catch(){
}
iii.在多個catch時只執行一個,自上而下遇到的第一個異常所對應的catch
如果沒有對應的catch,則先執
行finally後在拋出,沒有finally則直接拋出,定義多個catch可精確地定位異常。如果為子類的異常定
義了特殊的catch塊,而父類的異常則放在另外一個catch塊中,此時,必須滿足以下規則:子類異常的處
理塊必須在父類異常處理塊的前面,否則會發生編譯錯誤。所以,越特殊的異常越在前面處理,越普遍的
異常越在後面處理。這類似於制訂防火牆的規則次序:較特殊的規則在前,較普通的規則在後。
throws——–聲明方法拋出異常
1、說明:當不知道在當前代碼中如何處理的時候,可以選擇用throws將異常交給上層調用者處理
2、基本格式:
類型 方法名(形參列表)throws 異常列表(逗號隔開){
//代碼
}
例:
//手工拋出異常實例
public class JavaThrow1{
public static void main(String[] args){
System.out.print(” Now”);
try{
System.out.print(” is”);
throw new NullPointerException();//直接拋出異常轉到catch進行處理
//System.out.println(“This will not excute!”);//有throw這句執行不到
}catch (NullPointerException e){
System.out.print(” the”);
}
System.out.print(” time.\n”);
}
}
//自動拋異常
public class ExTest {
public static void main(String[] args){
String s=null;
try{
System.out.println(“0”);
int i=s.length();//自動拋異常–空指針異常
System.out.println(“2”);
}finally{
System.out.println(“1”);
}
}
}
例:——–throws
public class ExceptionTest4{
public static void p() throws ArithmeticException{
//間接拋出異常,自己並未處理,讓方法的調用者來處理
int i;
i=4/0;//可能發生異常
System.out.println(“8”);
}
public static void main(String[] args){
try{
try{
p();//方法的直接調用調用者捕獲異常處理
}catch(ArithmeticException e){
System.out.println(“Divider is zero !”);
}
}catch(RuntimeException e){
System.out.println(“4”);
}
}
}
v.java異常處理機制
答:程序出現想數組角標越界,空指針等錯誤時,JAVA就會用異常Throwable
來描述這些錯誤,Throwable繼承了Object類,同時實現了Serializable接口,
根據出現的問題是否可以通過程序來解決。把Throwable分為Error錯誤和Exception異常,Exception根據編譯時是否會被檢
測分為運行時異常RuntimeException和已檢測異常CheckedException。異常的處理方
式有兩種,在發生異常的地方直接使用catch處理,或者將異常拋出給調用者,讓調用者來處理。
1、檢查性異常——程序正確,但因為外在的環境條件不滿足引發。例如:用
戶錯誤及I/O問題—-程序試圖打開一個並不存在的遠程Socket端口。這不是程序
本身的邏輯錯誤,而很可能是遠程機器名字錯誤(用戶拼寫錯誤)。對商用軟件系統,
程序開發者必須考慮並處理這個問題。JAVA編譯器強制要求處理這類異常,如果不
捕獲這類異常,程序將不能被編譯。
2、運行期異常——這意味著程序存在bug,如數組越界,0被除,入參不滿足規
范…..這類異常需要更改程序來避免,JAVA編譯器強制要求處理這類異常。
3、錯誤——一般很少見,也很難通過程序解決。它可能源於程序的bug,但一般
更可能源於環境問題,如內存耗盡。錯誤在程序中無須處理,而有運行環境處理。
當jdk內置異常類型不能滿足系統需求時,我們需要自定義異常,如:
public class MyExceptionTest {
public static void main(String[] args) {
MyExceptionTest mt = new MyExceptionTest();
mt.manager();
}
public void registe(int num) throws MyException{
if(num<0){
throw new MyException("人數為負數",3);
}
System.out.println(" 登記人數為:"+num);
}
public void manager(){
try{
registe(-100);
}catch (MyException e){
System.out.println("登記類型出錯:"+e.getId());
e.printStackTrace();
}
System.out.println(" 操作結束!");
}
}
class MyException extends Exception{
private int id;
public MyException(){}
public MyException(String message,int id){
super(message);//調用父類的getMessage()
//父類中已經定義了getMessage()可以直接使用———–該方法為Exception繼承Throwable的
this.id=id;
}
public int getId(){
return id;
}
}
自定義異常類必須要繼承Exception/RuntimeException,如果該異常的發生無法再繼續進行運算,就讓它繼承RuntimeException
繼承的原因是為了讓該類自定義類具備可拋型,讓該類具備操作異常的共性方法
自定義異常:按照JAVA的OO思想,將程序中出現的特有問題進行封裝
IOException——————–輸入輸出異常
ClassNotFoundException——-找不到類異常
NumberFormatException———字符串到數字格式的異常
FileNotfoundException———–文件找不到異常
NoSuchMethodException—————請求方法異常
運行時異常:RuntimeException
SecurityException———–試圖違反安全性異常
NullPointerException—-沒有實例化卻調用其屬性和方法————–空指針異常
ArrayIndexOfBoundsException———數組越界異常
StringIndexOfBoundsException———字符串越界異常
ArithmeticException————–算數異常/除數為零異常
NullPointerException——-試圖查找null異常
Main方法通常情況下不能把異常拋給JVM
Super a = new subclass();//向上轉型—-
—overload看左邊,override看右邊
———————————–多態針對的是方法
異常的好處:1、將問題進行封裝
2、將正常流程代碼和問題代碼進行分離,方便閱讀
處理原則:
1、處理方式有:try或者throws
2、調用到拋出異常的功能時,拋出幾個處理幾個(一個try對應多個catch)
3、多個catch,父類的catch放到最後
4、Catch內,需要定義針對性的處理方式,不要簡單的定義printStackTrace輸出語句,也不要不寫
5、當鋪獲到的異常,本功能處理不了時,可以繼續在catch中拋出
6、 例:
try{
throw new AException();
}catch(AException e){
throw e;
}
7、如果異常在內部被處理(catch),外部則不需要拋出
基本格式:catch用來處理異常,如果該異常為檢測時異常時,必須要處理或者拋出
異常繼承時,子類只能拋出父類的異常或者該異常的子類/子集異常,也可以不拋出異常
異常的注意事項
1、在子父類覆蓋時,
a)子類拋出的異常必須是父類異常的子類或子集
b)如果父類或接口沒有異常拋出時,子類覆蓋出現異常,只能try不能拋
c)如果父類中是RuntimeException時,子類可以不用拋出異常,反之,子類為RuntimeException異常,父類為其異常的子類或自己都可以編譯通過
1、throw 與throws
throw 後跟異常對象(只能有一個),throws後跟異常類(多個時用逗號隔開);
位置:throw用在方法體中,代表手工拋異常,throws用在方法聲明上,代表該方法可能發生異常
2、RuntimeException和CheckedException的區別
前者可以不在方法上聲明也可以不處理,後者必須要處理或者拋出