Java面向物件特性總結
1.面對物件與面對過程的區別
什麼是封裝?我看到過這樣一個例子:
我要用洗衣機洗衣服,只需要按一下開關和洗滌模式就可以了。有必要了解洗衣機內 部的結構嗎?有必要碰電動機嗎?有必要了解如何通電的嗎?
如果是對於面向過程來說,這些你都得知道。“吾生也有涯,而知也無涯”,面向物件的封裝與莊子的思想遙相呼應:用有限的時間去做更適合的事情。
面對過程是軟體開發的先驅者,但其侷限性不能滿足當今的主流市場需求。
面對過程注重微觀,每一步都親力親為;面對物件注重巨集觀,更加偏向於整體的流程。
效能:面對過程執行效率更高。Java是編譯成位元組碼給JVM執行,而面向過程直接編譯成機器碼執行
複用性:面對物件的封裝,繼承極大的擴充套件了程式碼的複用性
2.面對物件特徵——封裝
封裝的核心思想是隱藏實現,暴露介面。
封裝的目的:
- 解耦(符合迪米特法則)
- 保護資料安全(通過getter方法來獲取類中屬性值)
- 訪問許可權修飾符
修飾符 | 許可權範圍
public | 本類,子類,本包,外部包
protected | 本類,子類,本包
default | 本類,子類
private | 本類
3.面對物件特徵——繼承
繼承主要目的是實現程式碼複用。
特性:
- 子類具有父類非private的屬性和方法
- 子類可以擴充套件自己的屬性和方法
構造器的繼承問題
- 構造器是不會被子類繼承的,但子類的物件在初始化時會預設呼叫父類的無參構造器。
- 當父類顯示寫了有參構造器,且沒有無參構造器。子類繼承父類的時候必須顯示的呼叫父類的有參構造器。呼叫的方式可以使用super(a,b)來呼叫。
static修飾符的繼承問題
子類是不會繼承父類被static修飾的方法和變數,但是可以呼叫。
super 與 this 關鍵字
super關鍵字:我們可以通過super關鍵字來實現對父類成員的訪問,用來引用當前物件的父類。
this關鍵字:指向自己的引用。
final關鍵字
final 關鍵字宣告類可以把類定義為不能繼承的,即最終類;或者用於修飾方法,該方法不能被子類重寫:
- 方法不能重寫
- 類不能繼承
- final標記的變數(成員變數或區域性變數)即稱為常量。名稱大寫,且只 能被賦值一次。
子類物件例項化過程
new出一個子類物件的時候,必須先new出一個父類物件。子類在呼叫構造方法時,會先呼叫父類的構造方法。(預設)
如果不寫構造方法,編譯器預設加上一個無參構造器。如果寫了構造器,編譯器不會新增。
如果寫了有參構造器,子類就必須呼叫父類的構造方法。super(引數)。
如果同時有有參和無參構造器,那麼會預設呼叫無參。也可以自定義呼叫有參。
4.面對物件特徵——多型
提高了程式碼的通用性。
多型分為編譯時多型(方法過載)和執行時多型(方法重寫)。
- 過載與重寫
重寫指子類重寫父類的方法,方法名、引數列表必須相同,返回值範圍小於等於父類,丟擲的異常範圍小於等於父類,訪問修飾符範圍大於等於父類;如果父類方法訪問修飾符為 private或者final 則子類就不能重寫該方法。
過載發生在同一個類中,方法名必須相同,引數型別不同、個數不同、順序不同,方法返回值和訪問修飾符可以不同。
- 向上轉型
在多型中需要將子類的引用賦給父類物件,只有這樣該引用才既能可以呼叫父類的方法,又能呼叫子類的方法。
強制轉換
從子類到父類的型別轉換可以自動進行
從父類到子類的型別轉換必須通過造型(強制型別轉換)實現
無繼承關係的引用型別間的轉換是非法的
5.Object類
- Object類是所有Java類的根父類
- 如果在類的宣告中未使用extends關鍵字指明其父類,則預設父類 為java.lang.Object類(任何類都可以呼叫Object的方法)
package java.lang;
public class Object {
private static native void registerNatives();
static {
registerNatives();
}
public final native Class<?> getClass();
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
protected native Object clone() throws CloneNotSupportedException;
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws InterruptedException;
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}
public final void wait() throws InterruptedException {
wait(0);
}
protected void finalize() throws Throwable { }
}
Object的主要組成:
- public native int hashCode(); 取得hash碼
- equals(Object obj) 比較物件
- clone() 可用於複雜物件的深拷貝
==與equals的區別
== 既可以比較基本型別也可以比較引用型別。對於基本型別就是比較值,對於引用型別 就是比較記憶體地址。
equals的話,,如果該方法沒有被重寫過預設等同於==;
但是很多類預設重寫了:(比如String)
6.包裝類的使用
裝箱:基本資料型別--->包裝類
拆箱:包裝類--->基本資料型別
//裝箱
Integer t = new Integer(500);
//float to Float
Float f = new Float(“4.56”);
//拆箱
Integer x = 3;
int i = x.intValue();
//int to String
String str = String.valueOf(1);
//String to int
int x = Integer.parseInt(str1) ;
//包裝類 to String
Integer x = 8;
String str = x.toString();
or
String str = Integer.toString(3);
7.static關鍵字
在Java類中,可用static修飾屬性、方法、程式碼塊、內部類。
被修飾後的成員具備以下特點:
- 修飾的成員,被所有物件所共享
- 訪問許可權允許時,可不建立物件,直接用類名.屬性或方法呼叫
在static方法內部只能訪問類的static修飾的屬性或方法,不能訪問類的非static的結構。
static修飾的方法不能被重寫
static的應用:單例模式——靜態內部類
class StaticClassInner {
private StaticClassInner() {}
/*
使用靜態內部類,實現了延遲載入
呼叫getInstance()方法時,才會載入StaticClassInnerInstance。
通過JVM類載入執行緒安全的機制,避免了執行緒不安全。
*/
private static class StaticClassInnerInstance {
private static final StaticClassInner INSTANCE = new StaticClassInner();
}
public static StaticClassInner getInstance() {
return StaticClassInnerInstance.INSTANCE;
}
}
public class Operation
{
public static void main(String[] args) {
StaticClassInner doubleCheck1 = StaticClassInner.getInstance();
StaticClassInner doubleCheck2 = StaticClassInner.getInstance();
System.out.println(doubleCheck1.hashCode());
System.out.println(doubleCheck2.hashCode());
}
}
8.程式碼塊
對類或物件進行初始化。
程式碼塊可分為靜態程式碼塊和非靜態程式碼塊。(有無static修飾)
靜態程式碼塊:用static修飾的程式碼塊
- 可以有輸出語句。
- 可以對類的屬性、類的宣告進行初始化操作。
- 不可以對非靜態的屬性初始化。即:不可以呼叫非靜態的屬性和方法。
- 若有多個靜態的程式碼塊,那麼按照從上到下的順序依次執行。
- 靜態程式碼塊的執行要先於非靜態程式碼塊。
- 靜態程式碼塊隨著類的載入而載入,且只執行一次。
非靜態程式碼塊:沒有static修飾的程式碼塊
- 可以有輸出語句。
- 可以對類的屬性、類的宣告進行初始化操作。
- 除了呼叫非靜態的結構外,還可以呼叫靜態的變數或方法。
- 若有多個非靜態的程式碼塊,那麼按照從上到下的順序依次執行。
- 每次建立物件的時候,都會執行一次。且先於構造器執行。
9.抽象類和抽象方法
- 用abstract關鍵字來修飾一個類,這個類叫做抽象類。
- 用abstract來修飾一個方法,該方法叫做抽象方法。
10.interface
- 用interface來定義。
- 介面中的所有成員變數都預設是由public static final修飾的。
- 介面中的所有抽象方法都預設是由public abstract修飾的。
- 介面中沒有構造器。
- 介面採用多繼承機制。
定義Java類的語法格式:先寫extends,後寫implements
class SubClass extends SuperClass implements InterfaceA{ }
介面和抽象類之間的對比
11.內部類
在Java中,允許一個類的定義位於另一個類的內部,前者稱為內部類,後者 稱為外部類。
Inner class的名字不能與包含它的外部類類名相同;
成員內部類(static成員內部類和非static成員內部類)
class Outer {
private int s;
public class Inner {
public void mb() {
s = 100;
System.out.println("在內部類Inner中s=" + s);
}
}
public void ma() {
Inner i = new Inner();
i.mb();
} }
public class InnerTest {
public static void main(String args[]) {
Outer o = new Outer();
o.ma();
} }
區域性內部類(不談修飾符)
class 外部類{
方法(){
class 區域性內部類{ }
}
{class 區域性內部類
{ }
}
}
- 只能在宣告它的方法或程式碼塊中使用,而且是先聲明後使用。除此之外的任何地方 都不能使用該類
- 但是它的物件可以通過外部方法的返回值返回使用,返回值型別只能是區域性內部類 的父類或父介面型別
- 區域性內部類可以使用外部方法的區域性變數,但是必須是final的。
匿名內部類
匿名內部類不能定義任何靜態成員、方法和類,只能建立匿名內部類的一 個例項。一個匿名內部類一定是在new的後面,用其隱含實現一個介面或 實現一個類。
匿名內部類的特點
- 匿名內部類必須繼承父類或實現介面
- 匿名內部類只能有一個物件
- 匿名內部類物件只能使用多型形式引用
interface A{
public abstract void fun1();
}
public class Outer{
public static void main(String[] args) {
new Outer().callInner(new A(){
//介面是不能new但此處比較特殊是子類物件實現介面,只不過沒有為物件取名
public void fun1() {
System.out.println(“implement for fun1");
}
});// 兩步寫成一步了
}
public void callInner(A a) {
a.fun1();
}
}
12.異常處理
異常:在Java語言中,將程式執行中發生的不正常情況稱為“異常”。
(開發過程中的語法錯誤和邏輯錯誤不是異常)
Java程式在執行過程中所發生的異常事件可分為兩類:
- Error:Java虛擬機器無法解決的嚴重問題。如:JVM系統內部錯誤、資源 耗盡等嚴重情況。一般不編寫針對性 的程式碼進行處理。
- Exception: 其它因程式設計錯誤或偶然的外在因素導致的一般性問題,可以使 用針對性的程式碼進行處理。
異常處理機制一: try-catch-finally
在編寫程式時,經常要在可能出現錯誤的地方加上檢測的程式碼, 如進行x/y運算時,要檢測分母為0,資料為空,輸入的不是資料 而是字元等。過多的if-else分支會導致程式的程式碼加長、臃腫, 可讀性差。因此採用異常處理機制。
Java程式的執行過程中如出現異常,會生成一個異常類物件, 該異常物件將被提交給Java執行時系統,這個過程稱為丟擲 (throw)異常。
如果一個方法內丟擲異常,該異常物件會被拋給呼叫者方法中處 理。如果異常沒有在呼叫者方法中處理,它繼續被拋給這個呼叫 方法的上層方法。這個過程將一直繼續下去,直到異常被處理。 這一過程稱為捕(catch)異常。
程式設計師通常只能處理Exception,而對Error無能為力。
異常處理是通過try-catch-finally語句實現的。
try{
...... //可能產生異常的程式碼
}
catch( ExceptionName1 e ){
...... //當產生ExceptionName1型異常時的處置措施
}
catch( ExceptionName2 e ){
...... //當產生ExceptionName2型異常時的處置措施
}
[ finally{
...... //無論是否發生異常,都無條件執行的語句
} ]
如果丟擲的異常是IOException等型別的非執行時異常,則必須捕獲,否則 編譯錯誤。也就是說,我們必須處理編譯時異常,將異常進行捕捉,轉化為 執行時異常。
異常處理機制二: throws
- 如果一個方法(中的語句執行時)可能生成某種異常,但是並不能確定如何處理這 種異常,則此方法應顯示地宣告丟擲異常,表明該方法將不對這些異常進行處理, 而由該方法的呼叫者負責處理。
- 在方法宣告中用throws語句可以宣告丟擲異常的列表,throws後面的異常型別可 以是方法中產生的異常型別,也可以是它的父類。
- 重寫方法不能丟擲比被重寫方法範圍更大的異常型別。