1. 程式人生 > 實用技巧 >小Sun學Java之Java面向物件(上)

小Sun學Java之Java面向物件(上)

一、Java基礎程式設計

Sun筆記作為記錄,方便以後檢視。核心源自:尚矽谷:http://www.atguigu.com/

1.4 面向物件——上

1.4.1 類與物件

1. 面向物件學習的三條主線:
  • Java類及類的成員:屬性、方法、構造器;程式碼塊、內部類
  • 面向物件的大特徵:封裝性、繼承性、多型性、(抽象性)
  • 其它關鍵字:this、super、static、final、abstract、interface、package、import等
  • “大處著眼,小處著手”
2. 面向物件與面向過程(理解)

1.面向過程:強調的是功能行為,以函式為最小單位,考慮怎麼做。
2.面向物件:強調具備了功能的物件,以類/物件為最小單位,考慮誰來做。

舉例對比:人把大象裝進冰箱。

3. 完成一個專案(或功能)的思路:

4. 面向物件中兩個重要的概念:
  • 類:對一類事物的描述,是抽象的、概念上的定義

  • 物件:是實際存在的該類事物的每個個體,因而也稱為例項(instance)

    面向物件程式設計的重點是類的設計
    設計類,就是設計類的成員。

  • 二者的關係:
    物件,是由類new出來的,派生出來的。

5. 面向物件思想落地實現的規則
  • 建立類,設計類的成員
  • 建立類的物件
  • 通過“物件.屬性”或“物件.方法”呼叫物件的結構

補充:幾個概念的使用說明

  • 屬性 = 成員變數 = field = 域、欄位
  • 方法 = 成員方法 = 函式 = method
  • 建立類的物件 = 類的例項化 = 例項化類
6. 物件的建立與物件的記憶體解析

典型程式碼:

Person p1 = new Person();
Person p2 = new Person();
Person p3 = p1;//沒有新建立一個物件,共用一個堆空間中的物件實體。

說明:
如果建立了一個類的多個物件,則每個物件都獨立的擁有一套類的屬性。(非static的)
意味著:如果我們修改一個物件的屬性a,則不影響另外一個物件屬性a的值。

記憶體解析:

7. 匿名物件:我們建立的物件,沒顯式的賦給一個變數名。即為匿名物件

特點:匿名物件只能呼叫一次。
舉例:

    new Phone().sendEmail();
    new Phone().playGame();
		
	new Phone().price = 1999;
	new Phone().showPrice();//0.0
	
	應用場景:
	PhoneMall mall = new PhoneMall();

    //匿名物件的使用
    mall.show(new Phone());
    其中,
    class PhoneMall{
        public void show(Phone phone){
            phone.sendEmail();
            phone.playGame();
		}
	}
8. 理解"萬事萬物皆物件"
  1. 在Java語言範疇中,我們都將功能、結構等封裝到類中,通過類的例項化,來呼叫具體的功能結構
  • Scanner,String等
  • 檔案:File
  • 網路資源:URL
  1. 涉及到Java語言與前端Html、後端的資料庫互動時,前後端的結構在Java層面互動時,都體現為類、物件。
1.4.1.1 JVM記憶體結構(這裡只是簡單瞭解,詳細:JVM章節進行講解)

編譯完源程式以後,生成一個或多個位元組碼檔案。
我們使用JVM中的類的載入器和直譯器對生成的位元組碼檔案進行解釋執行。意味著,需要將位元組碼檔案對應的類載入到記憶體中,涉及到記憶體解析。

《JVM規範》

虛擬機器棧,即為平時提到的棧結構。我們將區域性變數儲存在棧結構中
堆,我們將new出來的結構(比如:陣列、物件)載入在對空間中。補充:物件的屬性(非static的)載入在堆空間中。
方法區:類的載入資訊、常量池、靜態域

1.4.2 類的結構之一:屬性

類的設計中,兩個重要結構之一:屬性

對比:屬性(成員變數) vs 區域性變數

1. 相同點:
  •  1.1 定義變數的格式:資料型別  變數名 = 變數值
    
  •  1.2 先宣告,後使用
    
  •  1.3 變數都其對應的作用域 
    
2. 不同點:

2.1 在類中宣告的位置的不同

  • 屬性:直接定義在類的一對{}內

  • 區域性變數:宣告在方法內、方法形參、程式碼塊內、構造器形參、構造器內部的變數

2.2 關於許可權修飾符的不同

  • 屬性:可以在宣告屬性時,指明其許可權,使用許可權修飾符。

  • 常用的許可權修飾符:private、public、預設、protected --->封裝性

  • 目前,大家宣告屬性時,都使用預設就可以了。

  • 區域性變數:不可以使用許可權修飾符。

2.3 預設初始化值的情況:

  •  ==屬性==:類的屬性,根據其型別,都預設初始化值。
    
  •  	整型(byte、short、int、long:0)
    
  •  	浮點型(float、double:0.0)
    
  •  	字元型(char:0  (或'\u0000'))
    
  •  	布林型(boolean:false)
    
  •  	引用資料型別(類、陣列、介面:null)
    
  •  ==區域性變數==:沒預設初始化值。
    
  •  	意味著,我們在呼叫區域性變數之前,一定要顯式賦值。
    
  •  	特別地:形參在呼叫時,我們賦值即可。
    

2.4 在記憶體中載入的位置:

  •  ==屬性==:載入到堆空間中   (非static)
    
  •  ==區域性變數==:載入到棧空間
    

補充:回顧變數的分類:

  • 方式一:按照資料型別:
  • 方式二:按照在類中宣告的位置:

1.4.3 類的結構之二:方法

1. 關鍵字:return

return關鍵字:

  • 使用範圍:使用在方法體中

  • 作用:

    • 結束方法
    • 針對於返回值型別的方法,使用"return 資料"方法返回所要的資料

注意點:return關鍵字後面不可以宣告執行語句。

2.方法的過載
  1. 方法的過載的概念
    定義:在同一個類中,允許存在一個以上的同名方法,只要它們的引數個數或者引數型別不同即可。

總結:"兩同一不同":同一個類、相同方法名
引數列表不同:引數個數不同,引數型別不同

  1. 構成過載的舉例:
    舉例一:Arrays類中過載的sort() / binarySearch();PrintStream中的println()
    舉例二:

    //如下的4個方法構成了過載
    public void getSum(int i,int j){
    System.out.println("1");
    }

    public void getSum(double d1,double d2){
    System.out.println("2");
    }

    public void getSum(String s ,int i){
    System.out.println("3");
    }

    public void getSum(int i,String s){
    System.out.println("4");
    }

不構成過載的舉例:

//如下的3個方法不能與上述4個方法構成過載
//	public int getSum(int i,int j){
//		return 0;
//	}
	
//	public void getSum(int m,int n){
//		
//	}
	
//	private void getSum(int i,int j){
//		
//	}
  1. 如何判斷是否構成方法的過載?
    嚴格按照定義判斷:兩同一不同。
    跟方法的許可權修飾符、返回值型別、形參變數名、方法體都沒關係!
  2. 如何確定類中某一個方法的呼叫:
    方法名 ---> 引數列表

面試題:各種區別大集合:

參考:https://blog.csdn.net/weixin_43495390/article/details/86533482

方法的過載與重寫的區別?

throws\throw

String\StringBuffer\StringBuilder

Collection\Collections

final\finally\finalize
...

抽象類、介面

sleep() / wait()
3.可變個數形參的方法
  1. 使用說明:
  • 1.jdk 5.0新增的內容
  • 2.具體使用:
  • 2.1 可變個數形參的格式:資料型別 ... 變數名
  • 2.2 當呼叫可變個數形參的方法時,傳入的引數個數可以是:0個,1個,2個,。。。
  • 2.3 可變個數形參的方法與本類中方法名相同,形參不同的方法之間構成過載
  • 2.4 可變個數形參的方法與本類中方法名相同,形參型別也相同的陣列之間不構成過載。換句話說,二者不能共存。
  • 2.5 可變個數形參在方法的形參中,必須宣告在末尾
  • 2.6 可變個數形參在方法的形參中,最多隻能宣告一個可變形參。
  1. 舉例說明:

    public void show(int i){
    }

    public void show(String s){
    System.out.println("show(String)");
    }

    public void show(String ... strs){
    System.out.println("show(String ... strs)");

     for(int i = 0;i < strs.length;i++){
     	System.out.println(strs[i]);
     }
    

    }
    //不能與上一個方法同時存在
    // public void show(String[] strs){
    //
    // }
    呼叫時:
    test.show("hello");
    test.show("hello","world");
    test.show();
    test.show(new String[]{"AA","BB","CC"});

4.Java的值傳遞機制
  1. 針對於方法內變數的賦值舉例:

     System.out.println("***********基本資料型別:****************");
     int m = 10;
     int n = m;
     System.out.println("m = " + m + ", n = " + n);
     
     n = 20;
     
     System.out.println("m = " + m + ", n = " + n);
     
     System.out.println("***********引用資料型別:****************");
     
     Order o1 = new Order();
     o1.orderId = 1001;
     
     Order o2 = o1;//賦值以後,o1和o2的地址值相同,都指向了堆空間中同一個物件實體。
     
     System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);
     
     o2.orderId = 1002;
     
     System.out.println("o1.orderId = " + o1.orderId + ",o2.orderId = " +o2.orderId);
    

規則:
如果變數是基本資料型別,此時賦值的是變數所儲存的資料值。
如果變數是引用資料型別,此時賦值的是變數所儲存的資料的地址值。

  1. 針對於方法的引數概念
    形參:方法定義時,宣告的小括號內的引數
    實參:方法呼叫時,實際傳遞給形參的資料

  2. java中引數傳遞機制:值傳遞
    規則:

  • 如果引數是基本資料型別,此時實參賦給形參的是實參真實儲存的資料值。
  • 如果引數是引用資料型別,此時實參賦給形參的是實參儲存資料的地址值。

推廣:
如果變數是基本資料型別,此時賦值的是變數所儲存的資料值。
如果變數是引用資料型別,此時賦值的是變數所儲存的資料的地址值。

  1. 典型例題與記憶體解析:
    【例題1】

【例題2】

5.遞迴方法
  • 定義:
    遞迴方法:一個方法體內呼叫它自身。
  • 如何理解遞迴方法?

方法遞迴包含了一種隱式的迴圈,它會重複執行某段程式碼,但這種重複執行無須迴圈控制。
遞迴一定要向已知方向遞迴,否則這種遞迴就變成了無窮遞迴,類似於死迴圈。

  • 舉例:

    // 例1:計算1-n之間所自然數的和
    public int getSum(int n) {// 3
    if (n == 1) {
    return 1;
    } else {
    return n + getSum(n - 1);
    }

    }

    // 例2:計算1-n之間所自然數的乘積:n!
    public int getSum1(int n) {

      if (n == 1) {
      	return 1;
      } else {
      	return n * getSum1(n - 1);
      }
    

    }

    //例3:已知一個數列:f(0) = 1,f(1) = 4,f(n+2)=2f(n+1) + f(n),
    //其中n是大於0的整數,求f(10)的值。
    public int f(int n){
    if(n == 0){
    return 1;
    }else if(n == 1){
    return 4;
    }else{
    // return f(n + 2) - 2 * f(n + 1);
    return 2
    f(n - 1) + f(n - 2);
    }
    }

    //例4:斐波那契數列

    //例5:漢諾塔問題

    //例6:快排

1.4.4 面向物件的特徵一:封裝性

面向物件的特徵一:封裝與隱藏

  1. 為什麼要引入封裝性?
  • 我們程式設計追求“高內聚,低耦合”。
    高內聚 :類的內部資料操作細節自己完成,不允許外部干涉;
    低耦合 :僅對外暴露少量的方法用於使用。
  • 隱藏物件內部的複雜性,只對外公開簡單的介面。便於外界呼叫,從而提高系統的可擴充套件性、可維護性。通俗的說,把該隱藏的隱藏起來,該暴露的暴露出來。這就是封裝性的設計思想。
  1. 問題引入:
    當我們建立一個類的物件以後,我們可以通過"物件.屬性"的方式,對物件的屬性進行賦值。這裡,賦值操作要受到屬性的資料型別和儲存範圍的制約。除此之外,沒其他制約條件。但是,在實際問題中,我們往往需要給屬性賦值加入額外的限制條件。這個條件就不能在屬性宣告時體現,我們只能通過方法進行限制條件的新增。(比如:setLegs()同時,我們需要避免使用者再使用"物件.屬性"的方式對屬性進行賦值。則需要將屬性宣告為私有的(private).
    -->此時,針對於屬性就體現了封裝性。
  2. 封裝性思想具體的程式碼體現:
體現一:將類的屬性xxx私化(private),同時,提供公共的(public)方法來獲取(getXxx)和設定(setXxx)此屬性的值
private double radius;
public void setRadius(double radius){
	this.radius = radius;
}
public double getRadius(){
	return radius;
}
體現二:不對外暴露的私有的方法
體現三:單例模式(將構造器私有化)
體現四:如果不希望類在包外被呼叫,可以將類設定為預設的。
  1. Java規定的四種許可權修飾符
    4.1 許可權從小到大順序為:private < 預設 < protected < public
    4.2 具體的修飾範圍:

    4.3 許可權修飾符可用來修飾的結構說明:

4種許可權都可以用來修飾類的內部結構:屬性、方法、構造器、內部類
修飾類的話,只能使用:預設、public

1.4.5 類的結構之三:構造器

1.4.5.1 屬性賦值順序

  • 總結:屬性賦值的先後順序

    ① 預設初始化

    ② 顯式初始化

    ③ 構造器中初始化

    ④ 通過"物件.方法" 或 "物件.屬性"的方式,賦值

  • 以上操作的先後順序:① - ② - ③ - ④

1.4.5.2 JavaBean的概念

所謂JavaBean,是指符合如下標準的Java類:

  • 類是公共的

  • 一個無參的公共的構造器

  • 屬性,且對應的get、set方法

1.4.6 關鍵字:this

  1. 可以呼叫的結構:屬性、方法;構造器
  2. this呼叫屬性、方法:
    this理解為:當前物件 或 當前正在建立的物件
  • 在類的方法中,我們可以使用"this.屬性"或"this.方法"的方式,呼叫當前物件屬性或方法。但是,通常情況下,我們都擇省略"this."。特殊情況下,如果方法的形參和類的屬性同名時,我們必須顯式的使用"this.變數"的方式,表明此變數是屬性,而非形參。
  • 在類的構造器中,我們可以使用"this.屬性"或"this.方法"的方式,呼叫當前正在建立的物件屬性或方法。但是,通常情況下,我們都擇省略"this."。特殊情況下,如果構造器的形參和類的屬性同名時,我們必須顯式的使用"this.變數"的方式,表明此變數是屬性,而非形參。
  1. this呼叫構造器:
    ① 我們在類的構造器中,可以顯式的使用"this(形參列表)"方式,呼叫本類中指定的其他構造器
    ② 構造器中不能通過"this(形參列表)"方式呼叫自己
    ③ 如果一個類中有n個構造器,則最多有 n - 1構造器中使用了"this(形參列表)"
    ④ 規定:"this(形參列表)"必須宣告在當前構造器的首行
    ⑤ 構造器內部,最多隻能宣告一個"this(形參列表)",用來呼叫其他的構造器

1.4.7 關鍵字:package/import

  1. package的使用

1.1 使用說明:

  • 為了更好的實現專案中類的管理,提供包的概念
  • 使用package宣告類或介面所屬的包,宣告在原始檔的首行
  • 包,屬於識別符號,遵循識別符號的命名規則、規範(xxxyyyzzz)、“見名知意”
  • 每"."一次,就代表一層檔案目錄。
    1.2 舉例:
    舉例一:
    某航運軟體系統包括:一組域物件、GUI和reports子系統

舉例二:MVC設計模式

1.3 JDK中的主要包介紹:

  1. import的使用:
    import:匯入
    1. 在原始檔中顯式的使用import結構匯入指定包下的類、介面
    1. 宣告在包的宣告和類的宣告之間
    1. 如果需要匯入多個結構,則並列寫出即可
    1. 可以使用"xxx.*"的方式,表示可以匯入xxx包下的所結構
    1. 如果使用的類或介面是java.lang包下定義的,則可以省略import結構
    1. 如果使用的類或介面是本包下定義的,則可以省略import結構
    1. 如果在原始檔中,使用了不同包下的同名的類,則必須至少一個類需要以全類名的方式顯示。
    1. 使用"xxx.*"方式表明可以呼叫xxx包下的所結構。但是如果使用的是xxx子包下的結構,則仍需要顯式匯入
    1. import static:匯入指定類或介面中的靜態結構:屬性或方法。