1.面向對象的三大特性
繼承、封裝、多態 什么是繼承? 1.繼承是面向對象程序設計能夠提高軟件開發效率的重要原因之一。 2.繼承是具有傳遞性的,就像現實中孫子不僅長得像爸爸而且還像他爺爺。 3.繼承來的屬性和方法是隱式的,也就是在本類里面是看不見的。 5.一個接口可以有多個父類,也就是接口可以是多繼承。 實際項目開發中,一個類繼承于另一個類,那么前者就是后者的子類,反則反之。 什么是封裝? 對象數據和操作該對象的指令都是對象自身的一部分,能夠實現盡可能對外部隱藏數據。 實際項目開發中,使用封裝最多的就是實體類,常常和JavaBean(類必須是具體的和公共的,并且具有無參數的構造器)一起使用。 那么,實體類有那些東西呢? 答:私有的成員變量、無參數的構造器、有參數的構造器、setters和getters方法、重寫tostring方法、重寫hashCode和equals方法。 什么是多態? 1.多態就是對象擁有多種形態:引用多態和方法多態。 2.引用多態:父類的引用可以指向本類對象、父類的引用可以指向子類的對象。 3.方法多態:創建本類對象時,調用的方法為本類的方法;創建子類對象時,調用的方法為子類 重寫的方法或者繼承的方法。 4.存在多態的必要條件:繼承、重寫。 5.多態的作用是消除類型之間的耦合關系。在實際項目開發中,A類繼承B類,如果在A類中不重寫B類的方法的時候,輸出的仍舊是B類方法里面的信息(B b=new A());如果在A類中重寫B類的方法的時候,輸出的是A類方法里面的信息(B b=new A())。 2.final、finally、finalize的區別final是修飾符
被final修飾的類,就意味著不能再派生出新的子類,不能作為父類而被子類繼承。因此一個類不能既被abstract聲明,又被final聲明。將變量或方法聲明為final,可以保證他們在使用的過程中不被修改。被聲明為final的變量必須在聲明時給出變量的初始值,而在以后的引用中只能讀取。被final聲明的方法也同樣只能使用,不能重載。
finally是在異常處理時提供finally塊來執行任何清除操作 不管有沒有異常被拋出、捕獲,finally塊都會被執行。try塊中的內容是在無異常時執行到結束。catch塊中的內容,是在try塊內容發生catch所聲明的異常時,跳轉到catch塊中執行。finally塊則是無論異常是否發生,都會執行finally塊的內容,所以在代碼邏輯中有需要無論發生什么都必須執行的代碼,就可以放在finally塊中。
finalize是方法名 java技術允許使用finalize()方法在垃圾收集器將對象從內存中清除出去之前做必要的清理工作。這個方法是由垃圾收集器在確定這個對象沒有被引用時對這個對象調用的。它是在object類中定義的,因此所有的類都繼承了它。子類覆蓋finalize()方法以整理系統資源或者被執行其他清理工作。finalize()方法是在垃圾收集器刪除對象之前對這個對象調用的。
3.Exception、Error、運行時異常與一般異常有何異同 Throwable是所有Java程序中錯誤處理的父類,有兩種子類:Error和Exception。
Error表示由JVM所偵測到的無法預期的錯誤,由于這是屬于JVM層次的嚴重錯誤,導致JVM無法繼續執行,因此,這是不可捕捉到的,無法采取任何恢復的操作,頂多只能顯示錯誤信息。 Exception表示可恢復的例外,這是可捕捉到的。 Java提供了兩類主要的異常:runtime exception和checked exception
checked異常也就是我們經常遇到的IO異常,以及 SQL異常都是這種異常。對于這種異常,JAVA編譯器強制要求我們必需對出現的這些異常進行catch。所以,面對這種異常不管我們是否愿意,只能自己去寫一大堆catch塊去處理可能的異常。
出現runtime異常后,系統會把異常一直往上層拋,一直遇到處理代碼。如果沒有處理塊,到最上層,如果是多線程就由Thread.run()拋出,如果是單線程就被main()拋出。拋出之后,如果是線程,這個線程也就退出了。如果是主程序拋出的異常,那么這整個程序也就退出了。運行時異常是Exception的子類,也有一般異常的特點,是可以被catch塊處理的。只不過往往我們不對他處理罷了。也就是說,你如果不對runtime異常進行處理,那么出現運行時異常之后,要么是線程中止,要么是主程序終止。
如果不想終止,則必須捕捉所有的運行時異常,決不讓這個處理線程退出。隊列里面出現異常數據了,正常的處理應該是把異常數據舍棄,然后記錄日志。不應該由于異常數據而影響下面對正常數據的處理。在這個場景這樣處理可能是一個比較好的應用,但并不代表在所有的場景你都應該如此。如果在其它場景,遇到了一些錯誤,如果退出程序比較好,這時你就可以不太理會運行時異常,或者是通過對異常的處理顯式的控制程序退出。異常處理的目標之一就是為了把程序從異常中恢復出來。 幾種常見的運行時異常
1.Object x = new Integer(0);System.out.println((String)x);當試圖將對象強制轉換為不是實例的子類時,拋出改異常(ClassCastException)。 2.int a = 5/0;一個整數“除以零”時,拋出ArithmeticException異常。 3.String s = null;int size =s.size();當應用程序試圖在需要對象的地方使用null時,拋出NullPointerException異常。 4."hello".indexOf(-1);指示索引或者為負,或者超出字符串的大小,拋出StringIndexOutOfBoundsException異常。 5.String[] ss = new String[-1];如果應用程序試圖創建大小為負的數組,則拋出NegativeArraySizeException異常。 6.IllegalArgumentException拋出的異常表明向方法傳遞了一個不合法或不正確的參數。7.NumberFormatException當應用程序試圖將字符串轉換成一種數值類型,但該字符串不能轉換為適當格式時,拋出該異常。 4.int和Integer有什么區別,Integer的值緩存范圍,包裝(封裝)類,裝箱和拆箱int是基本類型,直接存數值,進行初始化時int類的變量初始為0。 Integer是對象,用一個引用指向這個對象,Integer的變量則初始化為null。 java兩種數據類型分類
原始數據類型,分為boolean,byte,int,char,long,short,double,float 引用數據類型,分為數組,類,接口 java為每個原始類型提供了封裝類:Boolean,Character,Byte,Short,Integer,Long,Float,Double 自動裝箱:將基本數據類型重新轉化為對象 Integer num = 9;9是基本數據類型,原則上是不能賦值給對象的,JDK5之后就可以這樣聲明了,自動將基本數據類型轉化為對應的封裝類。 自動拆箱:將對象重新轉化為基本數據類型 Integer num = 9;system.out.println(a--);因為對象是不能直接進行運算的,而要轉化為基本數據類型才能夠運算。 深入分析
Integer a = 128;Integer b = 128;system.out.println(a==b);//false Integer a = 4;Integer b = 5;system.out.println(a==b);//true 分析原因:歸結于Java對于Integer與int的自動裝箱和拆箱的設計,是一種模式:叫享元模式(flyweight)。加大對簡單數字的重利用,Java定義在自動裝箱時對于值在-128~127之間的值,他們被裝箱為Integer對象后,會存在內存中被重用,始終只有一個對象。 5.重載和重寫的區別
重載(Overload)
方法重載是指同一個類中的多個方法具有相同的名字,但這些方法具有不同的參數列表,即參數的數量或參數類型不能完全相同,返回類型可以相同也可以不同,無法以返回類型作為重載函數的區分標準。重載是一個類中多態性的一種表現。 重載規則
- 必須具有不同的參數列表;
- 可以有不同的返回類型,只要參數列表不同就可以了;
- 可以有不同的訪問修飾符;
- 可以拋出不同的異常。
重載的特點
- 在使用重載時只能通過不同的參數樣式。例如,不同的參數類型,不同的參數個數,不同的參數順序(當然,同一方法內的幾個參數類型必須不一樣,例如可以是fun(int,float),但是不能為fun(int,int));
- 不能通過訪問權限、返回類型、拋出的異常進行重載;
- 方法的異常類型和數目不會對重載造成影響;
- 對于繼承來說,如果某一方法在父類中是訪問權限是priavte,那么就不能在子類對其進行重載,如果定義的話,也只是定義了一個新方法,而不會達到重載的效果。
重寫(Override)
方法重寫是存在子父類之間的,子類定義的方法與父類中的方法具有相同的方法名字,相同的參數表和相同的返回類型。子類中不能重寫父類中的final方法,必須重寫父類中的abstract方法。 重寫規則
- 參數列表必須完全與被重寫的方法相同;
- 返回的類型必須與被重寫的方法的返回類型相同;
- 訪問修飾符的限制一定要大于被重寫方法的訪問修飾符(public>protected>default>private);
- 重寫方法一定不能拋出新的檢查異常或者比被重寫方法申明更加寬泛的檢查型異常。例如:父類的一個方法申明了一個檢查異常IOException,在重寫這個方法是就不能拋出Exception,只能拋出IOException的子類異常,可以拋出非檢查異常。
重寫的特點
- 覆蓋的方法的標志必須要和被覆蓋的方法的標志完全匹配,才能達到覆蓋的效果;
- 覆蓋的方法的返回值必須和被覆蓋的方法的返回一致;
- 覆蓋的方法所拋出的異常必須和被覆蓋方法的所拋出的異常一致,或者是其子類;
- 被覆蓋的方法不能為private,否則在其子類中只是新定義了一個方法,并沒有對其進行覆蓋。
6.繼承和實現
繼承
繼承就是子類繼承父類的特征和行為,使得子類對象(實例)具有父類的實例域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為。 繼承的特性
- 子類擁有父類非private的屬性,方法;
- 子類可以擁有自己的屬性和方法,即子類可以對父類進行擴展;
- 子類可以用自己的方式實現父類的方法;
- Java的繼承是單繼承,但是可以多重繼承,單繼承就是一個子類只能繼承一個父類,多重繼承就是,例如A類繼承B類,B類繼承C類,所以按照關系就是C類是B類的父類,B類是A類的父類,這是java繼承區別于C++繼承的一個特性;
- 提高了類之間的耦合性(繼承的缺點,耦合度高就會造成代碼之間的聯系)。
繼承關鍵字
繼承可以使用extends和implements這兩個關鍵字來實現繼承,而且所有的類都是繼承于java.lang.Object,當一個類沒有繼承的兩個關鍵字,則默認繼承object(這個類在java.lang包中,所以不需要import)祖先類。 extends關鍵字 在Java中,類的繼承是單一繼承,一個子類只能擁有一個父類,所以extends只能繼承一個類。 implements關鍵字 使用implements關鍵字可以變相的使java具有多繼承的特性,使用范圍為類繼承接口的情況,可以同時繼承多個接口(接口跟接口之間采用逗號分隔)。 7.接口和抽象類
接口 接口(英文:Interface),在JAVA編程語言中是一個抽象類型,是抽象方法的集合,接口通常以interface來聲明。一個類通過繼承接口的方式,從而來繼承接口的抽象方法。 接口并不是類,編寫接口的方式和類很相似,但是它們屬于不同的概念。類描述對象的屬性和方法。接口則包含類要實現的方法。 除非實現接口的類是抽象類,否則該類要定義接口中的所有方法。 接口無法被實例化,但是可以被實現。一個實現接口的類,必須實現接口內所描述的所有方法,否則就必須聲明為抽象類。另外,在Java中,接口類型可用來聲明一個變量,他們可以成為一個空指針,或是被綁定在一個以此接口實現的對象。
接口特性
- 接口中每一個方法也是隱式抽象的,接口中的方法會被隱式的指定為public abstract(其他修飾符都會報錯);
- 接口中可以含有變量,但是接口中的變量會被隱式的指定為public static final變量(用private修飾會報編譯錯誤);
- 接口中的方法是不能在接口中實現的,只能由實現接口的類來實現接口中的方法。
抽象類(abstract) 在面向對象的概念中,所有的對象都是通過類來描繪的,但是反過來,并不是所有的類都是用來描繪對象的,如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。 抽象類除了不能實例化對象之外,類的其它功能依然存在,成員變量、成員方法和構造方法的訪問方式和普通類一樣。 由于抽象類不能實例化對象,所以抽象類必須被繼承,才能被使用。也是因為這個原因,通常在設計階段決定要不要設計抽象類。 父類包含了子類集合的常見的方法,但是由于父類本身是抽象的,所以不能使用這些方法。 在Java中抽象類表示的是一種繼承關系,一個類只能繼承一個抽象類,而一個類卻可以實現多個接口。 抽象類特性
- 抽象類不能被實例化(初學者很容易犯的錯),如果被實例化,就會報錯,編譯無法通過。只有抽象類的非抽象子類可以創建對象;
- 抽象類中不一定包含抽象方法,但是有抽象方法的類必定是抽象類;
- 抽象類中的抽象方法只是聲明,不包含方法體,就是不給出方法的具體實現也就是方法的具體功能;
- 構造方法,類方法(用static修飾的方法)不能聲明為抽象方法;
- 抽象類的子類必須給出抽象類中的抽象方法的具體實現,除非該子類也是抽象類。
抽象類和接口的區別
- 抽象類中的方法可以有方法體,就是能實現方法的具體功能,但是接口中的方法不行;
- 抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是 public static final 類型的;
- 接口中不能含有靜態代碼塊以及靜態方法(用static修飾的方法),而抽象類是可以有靜態代碼塊和靜態方法;
- 一個類只能繼承一個抽象類,而一個類卻可以實現多個接口;
- 接口中所有的方法默認都是抽象的,而抽象類可以同時包含抽象和非抽象的方法;
- 一個類要實現某個接口,必須實現這個接口聲明的所有方法。而一個類不需要實現抽象父類中聲明的所有方法,不過,這時候這個類也必須聲明為抽象類;
- 抽象類可以實現接口,而且不需要實現接口中的方法;
- 接口中的成員默認是public的,而抽象類的成員可以是private,protected或public的;
- 接口是絕對抽象的,不可實例化,抽象類也不可以實例化,但可以在main方法中觸發實例化(注:通過匿名類實現)。
8.傳引用和傳值 當對象通過傳值調用時,傳遞的是這個對象的一個拷貝。因此,即使函數修改這個對象,也不會影響原對象的值。 當對象通過傳引用調用時,對象本身沒有被傳遞,而傳遞的是對象的一個引用。因此,外部函數對這個對象的修改,也會反映到任何出現這個對象的地方。 傳值
傳值就是指將一個值傳遞到方法的內部。例如int a = 5,那么也就是給int型變量a賦值,值為5.如果一個方法,將這個變量傳進方法的內部,則進行的就是傳值。在java中,有8種基本數據類型,它們分別為:int、long、float、double、char、boolean、short、byte.這8種基本的數據類型作為參數進行傳遞是,都是進行的傳值。除此之外,還有一種特殊的情況,String。本身String是一個引用類型,很多人認為在向方法中傳遞String類型參數時,是進行傳引用。其實在這里,String可以看做為一個包裝類,因為String其本身就是通過字符數組實現的,那么它在實現參數傳遞的時候,也就是以char型數據的方式進行的,也就是進行傳值。
傳引用
java中的引用可以初步的理解為地址。也是在new了一個對象后,該對象是存在JVM的Heap區,也就是堆。那么必然有一個地址要指向這個對象的在JVM中的位置,那么,指向這個對象的這個地址就可以簡單的理解為“引用”。 9.String、StringBuilder和StringBuffer
String
- String類是final類,也即意味著String類不能被繼承,并且它的成員方法都默認為final方法;
- String類的實現是通過char數組來保存字符串的;
- 對String對象的任何改變都不影響到原對象,相關的任何改變操作都會生成新的對象。
StringBuilder、StringBuffer
StringBuffer和StringBuilder類的對象能夠被多次的修改,并且不產生新的未使用對象。 這三個類之間的區別主要是在兩個方面,即運行速度和線程安全這兩方面。
運行速度
首先說運行速度(執行速度),在這方面運行速度快慢為:StringBuilder>StringBuffer>String,String為字符串常量,而StringBuilder和StringBuffer均為字符串變量,即String對象一旦創建之后該對象是不可更改的,但后兩者的對象是變量,是可以更改的。 線程安全 在線程安全上,StringBuilder是線程不安全的,而StringBuffer是線程安全的。如果一個StringBuffer對象在字符串緩沖區被多個線程使用時,StringBuffer中很多方法可以帶有synchronized關鍵字,所以可以保證線程是安全的,但StringBuilder的方法則沒有該關鍵字,所以不能保證線程安全,有可能會出現一些錯誤的操作。所以如果要進行的操作是多線程的,那么就要使用StringBuffer,但是在單線程的情況下,還是建議使用速度比較快的StringBuilder。 總結 - String:適用于少量的字符串操作的情況;
- StringBuilder:適用于單線程下在字符緩沖區進行大量操作的情況;
- StringBuffer:適用多線程下在字符緩沖區進行大量操作的情況。
10.構造函數、構造函數重載和復制構造函數?
構造函數 處理對象的初始化,是一種特殊的成員函數,與其他函數不同,不需要用戶來調用它,在建立對象時自動執行。 - 每建立一個對象,就調用一次構造函數;
- 構造函數沒有返回值,因此也沒有類型,作用只是對對象進行初始化;
- 構造函數不需要被用戶調用,也不能被用戶調用。
構造函數重載
與構造函數具有相同的名字,而參數的個數或參數類型不相同。 復制構造函數
Java不支持像C++中那樣的復制構造函數,這個不同點是因為如果你不自己寫構造函數的情況下,Java不會創建默認的復制構造函數。
|