1,面對對象與面對過程的區別
什么是封裝?我看到過這樣一個例子:
我要用洗衣機洗衣服,只需要按一下開關和洗滌模式就可以了。有必要了解洗衣機內 部的結構嗎?有必要碰電動機嗎?有必要了解如何通電的嗎?
如果是對於面向過程來說,這些你都得知道。“吾生也有涯,而知也無涯”,面向對象的封裝與庄子的思想遙相呼應:用有限的時間去做更多的事情。
面對過程是軟件開發的先驅者,但其局限性不能滿足當今的主流市場需求。
-
面對過程注重微觀,每一步都親力親為;面對對象注重宏觀,更加偏向於整體的流程。
-
性能:面對過程執行效率更高。Java是編譯成字節碼給JVM運行,而面向過程直接編譯成機器碼執行
-
復用性:面對對象的封裝,繼承極大的擴展了代碼的復用性
2,面對對象特性
2.1,封裝
【隱藏實現,暴露接口】
-
解耦
-
通過訪問修飾符保證數據安全
-
訪問權限修飾符
修飾符 | 權限范圍 |
---|---|
public | 本類,子類,本包,外部包 |
protected | 本類,子類,本包 |
default | 本類,子類 |
private | 本類 |
2.2,繼承
【實現代碼復用】
但同時增強了類之間的耦合。子類可以繼承父類非私有的屬性和方法,並且可以擴展自己的屬性和方法。
構造器的繼承問題
- 構造器是不會被子類繼承的,但子類的對象在初始化時會默認調用父類的無參構造器。
- 當父類顯示寫了有參構造器,且沒有無參構造器。子類繼承父類的時候必須顯示的調用父類的有參構造器。調用的方式可以使用super(a,b)來調用。
子類,父類初始化過程
原則:靜態優於非靜態,父類優於子類
-
父類靜態變量,靜態語句塊
-
子類靜態變量,靜態語句塊
-
父類非靜態代碼塊,構造器
-
子類非靜態代碼塊,構造器
class Base {
// 1.父類靜態代碼塊
static {
System.out.println("Base static block!");
}
// 3.父類非靜態代碼塊
{
System.out.println("Base block");
}
// 4.父類構造器
public Base() {
System.out.println("Base constructor!");
}
}
public class Derived extends Base {
// 2.子類靜態代碼塊
static{
System.out.println("Derived static block!");
}
// 5.子類非靜態代碼塊
{
System.out.println("Derived block!");
}
// 6.子類構造器
public Derived() {
System.out.println("Derived constructor!");
}
public static void main(String[] args) {
new Derived();
}
}
執行順序
Base static block!
Derived static block!
Base block
Base constructor!
Derived block!
Derived constructor!
2.3,多態
主要體現在方法重載和方法重寫上。
方法重載指同一個類中方法名相同,參數類型,個數不同;
方法重寫指子類重寫父類,要求方法,參數列表相同,父類用private或者final修飾的方法不能重寫。
【作用】
提高了代碼的通用性。
關於向上轉型
在多態中需要將子類的引用賦給父類對象,只有這樣該引用才既能可以調用父類的方法,又能調用子類的方法。
關於強制轉換
從子類到父類的類型轉換可以自動進行
從父類到子類的類型轉換必須通過造型(強制類型轉換)實現
無繼承關系的引用類型間的轉換是非法的
2.3,繼承之父——Object類
- Object類是所有Java類的根父類
- 如果在類的聲明中未使用extends關鍵字指明其父類,則默認父類 為java.lang.Object類(任何類都可以調用Object的方法)
【Object的主要組成】
- public native int hashCode(); 取得hash碼
- equals(Object obj) 比較對象
- clone() 可用於復雜對象的深拷貝
==與equals的區別
== 既可以比較基本類型也可以比較引用類型。對於基本類型就是比較值,對於引用類型 就是比較內存地址。
equals,通常會被重寫,比較引用類型的內容是否相同
但是很多類默認重寫了:(比如String)
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 { }
}
3,關鍵字
3.1,static關鍵字
static可以修飾方法,變量,代碼塊,類,前兩種應用更加常見。
static修飾方法
static修飾的方法稱為靜態方法,也稱類方法,可以直接通過類名.方法名直接訪問,不需要實例化對象訪問。
- 非static方法可以訪問static方法.
- static方法不能訪問非static方法
static修飾變量
static修飾的變量稱為靜態變量,也稱類變量,全局變量,可以直接通過類名.變量名直接訪問,不需要實例化對象訪問。
靜態變量和實例變量的區別?
- 靜態變量前要加 static 關鍵字,而實例變量前則不加。
- 實例變量屬於實例對象,只有實例化對象后才能使用
- 靜態變量屬於類,也稱類變量。可以直接通過類名引用。
static修飾符的繼承問題
子類是不會繼承父類被static修飾的方法和變量,但是可以調用。
static修飾代碼塊
代碼塊的作用:對類或對象進行初始化。
靜態代碼塊【static修飾】
- 不可以對非靜態的屬性初始化。即:不可以調用非靜態的屬性和方法。
- 靜態代碼塊的執行要先於非靜態代碼塊。
- 靜態代碼塊隨着類的加載而加載,且只執行一次
非靜態代碼塊
- 除了調用非靜態的結構外,還可以調用靜態的變量或方法。
- 每次創建對象的時候,都會執行一次。且先於構造器執行。
3.2,final關鍵字
final關鍵字可以修飾類,方法,變量。
final修飾類
不能被繼承
final修飾方法
方法不能被子類重寫
final修飾變量
修飾基本數據類型的變量,想當於定義了一個常量。
修飾引用類型的變量,固定棧,不固定堆,也就是引用變量的地址是不可變的,但是引用地址指向的堆中的內容是可變的。
final, finally, finalize 的區別。
- final 用於聲明屬性,方法和類,分別表示屬性不可變,方法不可重寫,類不可繼承。
- finally 是異常處理語句結構的一部分,表示總是執行
- finalize 是 Object 類的一個方法,用於回收對象
3.3,super 與 this 關鍵字
super關鍵字:我們可以通過super關鍵字來實現對父類成員的訪問,用來引用當前對象的父類。
this關鍵字:指向自己的引用。
4,interface與抽象類
4.1,interface定義
- 使用interface聲明
- 包含常量,抽象方法
- 接口中的所有變量都默認是由public static final修飾的(不可更改)
- 接口中的所有抽象方法都默認是由public abstract修飾的(不可更改)
- 接口中沒有構造器
- 接口采用多繼承機制
4.2,抽象類定義
- 使用abstract聲明
- 包含構造方法,抽象方法,普通方法,常量,變量
- 采用單繼承機制
- 雖然是類,但是不能實例化
- 抽象類可以沒有抽象方法,但有抽象方法的類一定是抽象類
4.3,抽象類和接口的相關問題
接口和抽象類的區別
- 聲明方式的區別:interface和abstract
- 繼承機制區別:單繼承和多繼承
- 包含的內容不同:
- interface只包含常量和抽象方法,常量默認用public static final修飾,抽象方法默認使用public abstract修飾
- abstract包含類的組成部分:構造器,方法,變量,常量。可以定義抽象方法(or not)
同時實現接口,繼承類的聲明順序
先寫extends,后寫implements
class SubClass extends SuperClass implements InterfaceA{ }
普通類和抽象類有哪些區別
- (是否可以包含抽象方法)抽象類可以包含抽象方法
- (是否可以實例化)普通類可以實例化對象
抽象類可以用final修飾嗎?
不能,抽象類的存在是讓其他類繼承的。使用final修飾就無法繼承。
5,內部類
在Java中,允許一個類的定義位於另一個類的內部,前者稱為內部類,后者 稱為外部類。
Inner class的名字不能與包含它的外部類類名相同;
內部類分為四種,分別是成員內部類,局部內部類,匿名內部類和靜態內部類。
5.1,【成員內部類】
- 內部類可以無限制的訪問外圍類的所有成員屬性和方法,包括private修飾
- 但是外圍類要訪問內部類的成員屬性和方法則需要通過內部類實例來訪問
- 成員內部類中不能存在
static
方法, 但是可以存在static
域, 前提是需要使用final
關鍵字進行修飾.
public class OuterClass {
private String str;
public void outerDisplay(){
System.out.println("outerClass...");
}
public class InnerClass{
public void innerDisplay(){
str = "chenssy..."; //使用外圍內的屬性
System.out.println(str);
outerDisplay(); //使用外圍內的方法
}
}
// 推薦使用getxxx()來獲取成員內部類,尤其是該內部類的構造函數無參數時
public InnerClass getInnerClass(){
return new InnerClass();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.getInnerClass();
inner.innerDisplay();
}
}
--------------------
chenssy...
outerClass...
5.2,【局部內部類】(在方法或者作用域里的類)
只能在聲明它的方法或代碼塊中使用
//定義在方法里:
public class Parcel5 {
public Destionation destionation(String str){
class PDestionation implements Destionation{
private String label;
private PDestionation(String whereTo){
label = whereTo;
}
public String readLabel(){
return label;
}
}
return new PDestionation(str);
}
public static void main(String[] args) {
Parcel5 parcel5 = new Parcel5();
Destionation d = parcel5.destionation("chenssy");
}
}
//定義在作用域內:
public class Parcel6 {
private void internalTracking(boolean b){
if(b){
class TrackingSlip{
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip(){
return id;
}
}
TrackingSlip ts = new TrackingSlip("chenssy");
String string = ts.getSlip();
}
}
public void track(){
internalTracking(true);
}
public static void main(String[] args) {
Parcel6 parcel6 = new Parcel6();
parcel6.track();
}
}
5.3,匿名內部類
一個匿名內部類一定是在new的后面,並且必須繼承一個父類或實現一個接口。
abstract class Person {
public abstract void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
public class Demo {
public static void main(String[] args) {
Thread t = new Thread() {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.print(i + " ");
}
}
};
t.start();
}
}
5.4, 【靜態內部類】
使用 static 修飾的內部類稱之為靜態內部類
它不能使用任何外部類的非 static 成員變量和方法。
public class OuterClass {
private String sex;
public static String name = "chenssy";
// 靜態內部類
static class InnerClass1{
// 在靜態內部類中可以存在靜態成員
public static String _name1 = "chenssy_static";
public void display(){
// 靜態內部類只能訪問外圍類的靜態成員變量和方法
// 不能訪問外圍類的非靜態成員變量和方法
System.out.println("OutClass name :" + name);
}
}
// 非靜態內部類
class InnerClass2{
// 非靜態內部類中不能存在靜態成員
public String _name2 = "chenssy_inner";
// 非靜態內部類中可以調用外圍類的任何成員,不管是靜態的還是非靜態的
public void display(){
System.out.println("OuterClass name:" + name);
}
}
// 外圍類方法
public void display(){
// 外圍類訪問靜態內部類:內部類
System.out.println(InnerClass1._name1);
// 靜態內部類 可以直接創建實例不需要依賴於外圍類
new InnerClass1().display();
// 非靜態內部的創建需要依賴於外圍類
OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();
// 方位非靜態內部類的成員需要使用非靜態內部類的實例
System.out.println(inner2._name2);
inner2.display();
}
public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.display();
}
}
----------------
Output:
chenssy_static
OutClass name :chenssy
chenssy_inner
OuterClass name:chenssy
6.異常處理
異常:在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后面的異常類型可 以是方法中產生的異常類型,也可以是它的父類。
- 重寫方法不能拋出比被重寫方法范圍更大的異常類型。