Java學習筆記(基礎二)

數組

基本瞭解

  • Java 語言中提供的數組是用來存儲固定大小的同類型元素
  • 數組(array)是多個相同類型的數據按照必定順序排列的集合,並使用一個名字命名,並經過編號的方式對這些數據進行同一的管理
  • 數組是引用數據類型,可是數組中的元素能夠是任意的數據類型
  • 建立數組對象會在內存中開闢一整塊連續的空間,而數組名中引用的時這塊內存空間中的首地址
  • 數組的長度一旦肯定就不可更改

基本使用

  • 聲明:dataType[] arrayRefVar; (推薦的方式)
  • 聲明2:dataType arrayRefVar[];

**Tip:建議使用 dataType[] arrayRefVar 的聲明風格聲明數組變量。 dataType arrayRefVar[] 風格是來自 C/C++ 語言 **java

  • 建立數組:arrayRefVar = new dataType[arraySize];
    • 使用 dataType[arraySize] 建立了一個數組。
    • 把新建立的數組的引用賦值給變量 arrayRefVar
  • 示例:
    • int[] array1 = new int[]{1, 2, 3}; (靜態初始化)
    • int[] array1 = {1, 2, 3}; (類型推斷)
    • String[] array2 = new String[3]; (動態初始化,數組的初始化和數組元素的的賦值操做分開進行)
    • array[number] 可使用下標的方式對數組內部數據進行賦值和讀取操做
  • 數組中的length屬性保存着該數組的長度
  • 數組中元素的默認值同相應變量的默認值

foreach遍歷

  • 代碼示例c++

    package study1;
    
    public class a {
    	
    	public static void main(String[] args) {
    		int[] a = {1, 2, 3, 4, 5};
    		
    		for(int i : a){
    			System.out.println(i);
    		}
    	}
    
    }

JVM內存結構

  • java虛擬機對內存區域的劃分算法

    • 第一,JVM分爲五個區域:虛擬機棧本地方法棧方法區程序計數器
    • 第二,JVM五個區中虛擬機棧、本地方法棧、程序計數器爲線程私有,方法區和堆爲線程共享區。圖中已經用顏色區分,綠色表示「通行」,橘黃色表示停一停(需等待)。
    • 第三,JVM不一樣區域的佔用內存大小不一樣,通常狀況下堆最大,程序計數器較小。那麼最大的區域會放什麼?固然就是Java中最多的「對象」了。
  • 堆(Heap)shell

    • 上面已經得出結論,堆內存最大,堆是被線程共享,堆的目的就是存放對象。幾乎全部的對象實例都在此分配。固然,隨着優化技術的更新,某些數據也會被放在棧上等。
    • 槍打出頭鳥,樹大招風。由於堆佔用內存空間最大,堆也是Java垃圾回收的主要區域(重點對象),所以也稱做「GC堆」(Garbage Collected Heap)。
    • 關於GC的操做,後面章節會詳細講,但正由於GC的存在,而現代收集器基本都採用分代收集算法,堆又被細化了。
    • 對於圖示的分析:
      • 第一,堆的GC操做採用分代收集算法。
      • 第二,堆區分了新生代和老年代;
      • 第三,新生代又分爲:Eden空間、From Survivor(S0)空間、To Survivor(S1)空間。
    • Java虛擬機規範規定,Java堆能夠處於物理上不連續的內存空間中,只要邏輯上是連續的便可。也就是說堆的內存是一塊塊拼湊起來的。要增長堆空間時,往上「拼湊」(可擴展性)便可,但當堆中沒有內存完成實例分配,而且堆也沒法再擴展時,將會拋出OutOfMemoryError異常。
  • 方法區(Method Area)編程

    • 方法區與堆有不少共性:線程共享、內存不連續、可擴展、可垃圾回收,一樣當沒法再擴展時會拋出OutOfMemoryError異常。
    • 正由於如此相像,Java虛擬機規範把方法區描述爲堆的一個邏輯部分,但目前其實是與Java堆分開的(Non-Heap)。
    • 方法區個性化的是,它存儲的是已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據。
    • 方法區的內存回收目標主要是針對常量池的回收和對類型的卸載,通常來講這個區域的回收「成績」比較難以使人滿意,尤爲是類型的卸載,條件至關苛刻,可是回收確實是有必要的。
  • 程序計數器(Program Counter Register)設計模式

    • 關於程序計數器咱們已經得知:佔用內存較小,現成私有。它是惟一沒有OutOfMemoryError異常的區域。
    • 程序計數器的做用能夠看作是當前線程所執行的字節碼的行號指示器,字節碼解釋器工做時就是經過改變計數器的值來選取下一條字節碼指令。其中,分支、循環、跳轉、異常處理、線程恢復等基礎功能都須要依賴計數器來完成。
    • Java虛擬機的多線程是經過線程輪流切換並分配處理器執行時間的方式來實現的,在任何一個肯定的時刻,一個處理器(對於多核處理器來講是一個內核)只會執行一條線程中的指令。
    • 所以,爲了線程切換後能恢復到正確的執行位置,每條線程都須要有一個獨立的程序計數器,各條線程之間的計數器互不影響,獨立存儲,咱們稱這類內存區域爲「線程私有」的內存。
    • 若是線程正在執行的是一個Java方法,這個計數器記錄的是正在執行的虛擬機字節碼指令的地址;若是正在執行的是Natvie方法,這個計數器值則爲空(Undefined)。
  • 虛擬機棧(JVM Stacks)數組

    • 虛擬機棧線程私有,生命週期與線程相同。安全

    • 棧幀(Stack Frame)是用於支持虛擬機進行方法調用和方法執行的數據結構。棧幀存儲了方法的局部變量表、操做數棧、動態鏈接和方法返回地址等信息。每個方法從調用至執行完成的過程,都對應着一個棧幀在虛擬機棧裏從入棧到出棧的過程。數據結構

    • 圖示解析多線程

      • 局部變量表(Local Variable Table)是一組變量值存儲空間,用於存放方法參數和方法內定義的局部變量。包括8種基本數據類型、對象引用(reference類型)和returnAddress類型(指向一條字節碼指令的地址)。

        其中64位長度的long和double類型的數據會佔用2個局部變量空間(Slot),其他的數據類型只佔用1個。

      • 若是線程請求的棧深度大於虛擬機所容許的深度,將拋出StackOverflowError異常;若是虛擬機棧動態擴展時沒法申請到足夠的內存時會拋出OutOfMemoryError異常。

      • 操做數棧(Operand Stack)也稱做操做棧,是一個後入先出棧(LIFO)。隨着方法執行和字節碼指令的執行,會從局部變量表或對象實例的字段中複製常量或變量寫入到操做數棧,再隨着計算的進行將棧中元素出棧到局部變量表或者返回給方法調用者,也就是出棧/入棧操做。

      • 動態連接:Java虛擬機棧中,每一個棧幀都包含一個指向運行時常量池中該棧所屬方法的符號引用,持有這個引用的目的是爲了支持方法調用過程當中的動態連接(Dynamic Linking)。

      • 方法返回:不管方法是否正常完成,都須要返回到方法被調用的位置,程序才能繼續進行。

  • 本地方法棧(Native Method Stacks)

    • 本地方法棧(Native Method Stacks)與虛擬機棧做用類似,也會拋出StackOverflowError和OutOfMemoryError異常。
    • 區別在於虛擬機棧爲虛擬機執行Java方法(字節碼)服務,而本地方法棧是爲虛擬機使用到的Native方法服務。
  • 總結

經典算法

  • 排序算法的優劣

    1. 時間複雜度:分析關鍵字的比較次數和記錄的移動次數
    2. 空間複雜度:分析排序算法中須要多少的輔助內存
    3. 穩定性:若兩個記錄A和B的關鍵字值相等,但排序後A、B的前後次序抱持不變,則稱這種排序算法是穩定的
  • 排序算法的分類

    • 內部排序:整個排序的過程當中,不須要藉助外部的存儲器,全部的排序操做都在內存中完成
    • 外部排序:參與排序的數據很是多,數據量很是大,計算機沒法把整個排序過程放在內存中完成,必須藉助外部存儲器。
  • 冒泡排序

    • 圖示

    • 示例代碼

      package study1;
      import java.util.Scanner;
      
      public class a {
      
      	public static void main(String[] args) {
      		int[] array1 = new int[10];
      		
      		System.out.println("請輸入須要排列的十個整數:");
      		Scanner getNumber = new Scanner(System.in);
      		for(int i=0; i<10; i++){
      			array1[i] = getNumber.nextInt();
      		}
      		
      		//冒泡排序
      		for(int i=0; i<10; i++){ 
      			for(int j=0; j<array1.length-1-i; j++){ 
      				if(array1[j] > array1[j+1]){
      					int temp = array1[j];
      					array1[j] = array1[j+1];
      					array1[j+1] = temp;
      				}
      			}
      		}
      		
      		System.out.println("排序完成!");
      		for(int i=0; i<10; i++){
      			System.out.println(array1[i]);
      		}
      	}
      
      }
    • 理解:

      • 思路:對相鄰的元素進行兩兩比較,順序相反則交換,這樣,每趟會將最小(或最大)的元素浮到數組最後面,最終達到總體有序。
      • 總結:N個數字要排序完成,總共進行N-1次排序,每i次的排序比較的次數爲(N-i)次,因此能夠用雙重循環語句,外層控制循環多少次,內層控制每一次的比較次數
      • 每次循環都會將本次參與循環的數字中的最大的一個放置在最後,於是在以後的每次排序中所參與的數字會一次減小。
  • 選擇排序

    • 圖示

    • 示例代碼

      package study1;
      
      public class a {
      
      	public static void main(String[] args) {
      		int[] array = {11, 21, 4, 65, 32, 7};
      		
      		for(int i=0; i<array.length; i++){
      			int minIndex = i;
      			for(int j=i; j<array.length; j++){
      				if(array[j] < array[minIndex]){
      					minIndex = j;
      				}
      			}
      			
      			int temp = array[minIndex];
      			array[minIndex] = array[i];
      			array[i] = temp;
      		}
      		
      		for(int k=0; k<array.length; k++){
      			System.out.println(array[k]);
      		}
      	}
      
      }
    • 理解:

      • 思路:每次遍歷數組,將所遍歷的最小值放置在最前,每次完成一次遍歷後,調整遍歷的起始位置(同時也是將剩餘數值篩選出所放置的位置),依次類推。
  • 插入排序

    • 圖示

    • 代碼示例

      package study1;
      
      public class a {
      
      	public static void main(String[] args) {
      		int[] array = {11, 21, 4, 65, 32, 7};
      		
              int current;
              for (int i = 0; i < array.length - 1; i++) {
                  current = array[i + 1]; // 當前排序到的元素
                  int preIndex = i; // 已經排序完成的最後一個元素的下標
                  // 將當前排序的元素與每一個已完成排序的元素比較
                  while (preIndex >= 0 && current < array[preIndex]) { 
                      array[preIndex + 1] = array[preIndex];
                      preIndex--;
                  }
                  array[preIndex + 1] = current;
              }
              
              for(int j=0; j<array.length; j++){
              	System.out.println(array[j]);
              }
      	}
      
      }
    • 理解:

      • 思路:將第一個元素視爲已經排序完成的元素,從第二個開始與排序好的元素比較,若待排序元素小於當前比較的排序好的元素,那麼將該比較大的排序好的元素向後移動,再次將待排序的元素與前一個已經完成排序的元素比較,重複此過程,直到待排序元素匹配到某個已完成排序的元素時添加到其後面。

二維數組

  • 靜態初始化:int[][] arr = new int[][]{{1, 2, 3}, {"a", "b", "c"}};

  • 動態初始化:String[][] arr2 = new String[2][3]; (第二個數組能夠暫時不去指定元素個數)

  • 注意:二維數組中的外層元素保存的是地址值(內層數組,數組爲引用數據類型),也就是說,若不給二維數組初始化將保存的值爲null(引用數據類型的默認值)

  • 楊輝三角

    package study1;
    
    public class a {
    
    	public static void main(String[] args) {
    		int[][] array = new int[10][];
    		for(int i=0; i<array.length; i++){
    			array[i] = new int[i + 1];
    			
    			array[i][0] = array[i][i] = 1;
    			if(i>1){
    				for(int j=1; j<array[i].length -1; j++){
    					array[i][j] = array[i-1][j-1] + array[i-1][j];
    				}
    			}
    		}		
    		for(int i=0; i<array.length; i++){
    			for(int j=0; j<array[i].length; j++){
    				System.out.print(array[i][j] + "\t");
    			}
    			System.out.println();
    		}
    	}
    
    }

數組的工具類

  • java.util.Arrays :操做數組的工具類
  • 經常使用方法示例
    • Arrays.equals(a, b) 比較兩個數組是否相同
    • Arrays.toString(a) 以字符串的形式輸出數組
    • Arrays.fill(a, value) 將數組中全部的元素替換爲指定的值
    • Arrays.sort(b) 將數組排序(快速排序)
    • Arrays.binarySearch(b, 1) 使用二分法查找有序數組(返回值爲複數則未找到指定元素)

面向對象

對象和類

  • 對象:對象是類的一個實例(對象不是找個女友),有狀態和行爲。例如,一條狗是一個對象,它的狀態有:顏色、名字、品種;行爲有:搖尾巴、叫、吃等。
  • 匿名對象 :爲被賦予名的對象,示例:new Phone().function···
  • :類是一個模板,它描述一類對象的行爲和狀態。

類的定義

  • 示例

    public class Dog{
      String breed;
      int age;
      String color;
      void barking(){
      }
     
      void hungry(){
      }
     
      void sleeping(){
      }
    }
  • 一個類能夠包含如下類型變量:

    • 局部變量:在方法、構造方法或者語句塊中定義的變量被稱爲局部變量。變量聲明和初始化都是在方法中,方法結束後,變量就會自動銷燬。
    • 成員變量:成員變量是定義在類中,方法體以外的變量。這種變量在建立對象的時候實例化。成員變量能夠被類中方法、構造方法和特定類的語句塊訪問。
    • 類變量:類變量也聲明在類中,方法體以外,但必須聲明爲 static 類型。

構造方法

  • 每一個類都有構造方法。若是沒有顯式地爲類定義構造方法,Java 編譯器將會爲該類提供一個默認構造方法。

  • 在建立一個對象的時候,至少要調用一個構造方法。構造方法的名稱必須與類同名,一個類能夠有多個構造方法。

  • 示例

    public class Puppy{
        public Puppy(){ // 沒有返回值
        }
     
        public Puppy(String name){
            // 這個構造器僅有一個參數:name
        }
    }

建立對象

  • 對象是根據類建立的。在Java中,使用關鍵字 new 來建立一個新的對象。建立對象須要如下三步:

    • 聲明:聲明一個對象,包括對象名稱和對象類型。
    • 實例化:使用關鍵字 new 來建立一個對象。
    • 初始化:使用 new 建立對象時,會調用構造方法初始化對象。
  • 示例

    public class Puppy{
       public Puppy(String name){
          //這個構造器僅有一個參數:name
          System.out.println("小狗的名字是 : " + name ); 
       }
       public static void main(String[] args){
          // 下面的語句將建立一個Puppy對象
          Puppy myPuppy = new Puppy( "tommy" );
       }
    }

源文件聲明規則

  • 一個源文件中只能有一個 public 類
  • 一個源文件能夠有多個非 public 類
  • 源文件的名稱應該和 public 類的類名保持一致。例如:源文件中 public 類的類名是 Employee,那麼源文件應該命名爲Employee.java。
  • 若是一個類定義在某個包中,那麼 package 語句應該在源文件的首行。
  • 若是源文件包含 import 語句,那麼應該放在 package 語句和類定義之間。若是沒有 package 語句,那麼 import 語句應該在源文件中最前面。
  • import 語句和 package 語句對源文件中定義的全部類都有效。在同一源文件中,不能給不一樣的類不一樣的包聲明。

Java包

  • 包主要用來對類和接口進行分類。當開發 Java 程序時,可能編寫成百上千的類,所以頗有必要對類和接口進行分類。

import語句

  • 在 Java 中,若是給出一個完整的限定名,包括包名、類名,那麼 Java 編譯器就能夠很容易地定位到源代碼或者類。import 語句就是用來提供一個合理的路徑,使得編譯器能夠找到某個類。
  • 示例:import java.util.*;
  • package 的做用就是 c++ 的 namespace 的做用,防止名字相同的類產生衝突。Java 編譯器在編譯時,直接根據 package 指定的信息直接將生成的 class 文件生成到對應目錄下。如 package aaa.bbb.ccc 編譯器就將該 .java 文件下的各個類生成到 ./aaa/bbb/ccc/ 這個目錄。

成員變量和類變量

  • 由static修飾的變量稱爲靜態變量,其實質上就是一個全局變量。若是某個內容是被全部對象所共享,那麼該內容就應該用靜態修飾;沒有被靜態修飾的內容,實際上是屬於對象的特殊描述。

  • 不一樣的對象的實例變量將被分配不一樣的內存空間, 若是類中的成員變量有類變量,那麼全部對象的這個類變量都分配給相同的一處內存,改變其中一個對象的這個類變量會影響其餘對象的這個類變量,也就是說對象共享類變量。

  • 成員變量和類變量的區別:

    1. 兩個變量的生命週期不一樣
    • 成員變量隨着對象的建立而存在,隨着對象的回收而釋放。

    • 靜態變量隨着類的加載而存在,隨着類的消失而消失。

    1. 調用方式不一樣
    • 成員變量只能被對象調用。

    • 靜態變量能夠被對象調用,還能夠被類名調用。

    1. 別名不一樣
    • 成員變量也稱爲實例變量。

    • 靜態變量也稱爲類變量。

    1. 數據存儲位置不一樣
    • 成員變量存儲在堆內存的對象中,因此也叫對象的特有數據。

    • 靜態變量數據存儲在方法區(共享數據區)的靜態區,因此也叫對象的共享數據

  • static關鍵字

    • static 關鍵字,是一個修飾符,用於修飾成員(成員變量和成員函數)。

      一、想要實現對象中的共性數據的對象共享。能夠將這個數據進行靜態修飾。

      二、被靜態修飾的成員,能夠直接被類名所調用。也就是說,靜態的成員多了一種調用方式。類名.靜態方式。

      三、靜態隨着類的加載而加載。並且優先於對象存在。

    • 注意

    一、有些數據是對象特有的數據,是不能夠被靜態修飾的。由於那樣的話,特有數據會變成對象的共享數據。這樣對事物的描述就出了問題。因此,在定義靜態時,必需要明確,這個數據是不是被對象所共享的。

    二、靜態方法只能訪問靜態成員,不能夠訪問非靜態成員。由於靜態方法加載時,優先於對象存在,因此沒有辦法訪問對象中的成員。

    三、靜態方法中不能使用this,super關鍵字。由於this表明對象,而靜態在時,有可能沒有對象,因此this沒法使用

    • 是否真的須要靜態成員

      一、成員變量。(數據共享時靜態化)

      該成員變量的數據是不是全部對象都同樣:

      若是是,那麼該變量須要被靜態修飾,由於是共享的數據。

      若是不是,那麼就說這是對象的特有數據,要存儲到對象中。

      二、成員函數。(方法中沒有調用特有數據時就定義成靜態)

      若是判斷成員函數是否須要被靜態修飾呢?

      只要參考,該函數內是否訪問了對象中的特有數據:

      若是有訪問特有數據,那方法不能被靜態修飾。

      若是沒有訪問過特有數據,那麼這個方法須要被靜態修飾。

    • 成員變量和靜態變量的區別

      一、成員變量所屬於對象。因此也稱爲實例變量。

      靜態變量所屬於類。因此也稱爲類變量。

      二、成員變量存在於堆內存中。

      靜態變量存在於方法區中。

      三、成員變量隨着對象建立而存在。隨着對象被回收而消失。

      靜態變量隨着類的加載而存在。隨着類的消失而消失。

      四、成員變量只能被對象所調用 。

      靜態變量能夠被對象調用,也能夠被類名調用。

      因此,成員變量能夠稱爲對象的特有數據,靜態變量稱爲對象的共享數據。

類的構造方法

  • 說明:
    • 當一個對象被建立時候,構造方法用來初始化該對象。構造方法和它所在類的名字相同,但構造方法沒有返回值。
    • 一般會使用構造方法給一個類的實例變量賦初值,或者執行其它必要的步驟來建立一個完整的對象。
    • 無論你是否自定義構造方法,全部的類都有構造方法,由於Java自動提供了一個默認構造方法,默認構造方法的訪問修改符和類的訪問修改符相同(類爲 public,構造函數也爲 public;類改成 protected,構造函數也改成 protected)。
    • 一旦你定義了本身的構造方法,默認構造方法就會失效。

​ 一、構造方法的名字和類名相同,而且沒有返回值。

​ 二、構造方法主要用於爲類的對象定義初始化狀態。

​ 三、咱們不能直接調用構造方法,必須經過new關鍵字來自動調用,從而建立類的實例。

​ 四、Java的類都要求有構造方法,若是沒有定義構造方法,Java編譯器會爲咱們提供一個缺省的構造方法,也就是不帶參數的構造方法。

  • new關鍵字的做用

    一、爲對象分配內存空間。

    二、引發對象構造方法的調用。

    三、爲對象返回一個引用。

方法

  • 命名規則

    • 方法的名字的第一個單詞應以小寫字母做爲開頭,後面的單詞則用大寫字母開頭寫,不使用鏈接符。例如:addPerson
    • 下劃線可能出如今 JUnit 測試方法名稱中用以分隔名稱的邏輯組件。一個典型的模式是:test< MethodUnderTest>_< state>,例如 testPop_emptyStack
  • 語法示例

    修飾符 返回值類型 方法名(參數類型 參數名){
        ...
        方法體
        ...
        return 返回值;
    }
    • 修飾符:修飾符,這是可選的,告訴編譯器如何調用該方法。定義了該方法的訪問類型。

    • 返回值類型 :方法可能會返回值。returnValueType 是方法返回值的數據類型。有些方法執行所需的操做,但沒有返回值。在這種狀況下,returnValueType 是關鍵字void

    • 方法名:是方法的實際名稱。方法名和參數表共同構成方法簽名。

    • 參數類型:參數像是一個佔位符。當方法被調用時,傳遞值給參數。這個值被稱爲實參或變量。參數列表是指方法的參數類型、順序和參數的個數。參數是可選的,方法能夠不包含任何參數。

    • 方法體:方法體包含具體的語句,定義該方法的功能。

  • 可變參數

    • 可變參數的聲明: typeName... parameterName

      • 在方法聲明中,在指定參數類型後加一個省略號(...)
      • 一個方法中只能指定一個可變參數,它必須是方法的最後一個參數。任何普通的參數必須在它以前聲明。
      • 該參數等同於一個相同類型數組(且與其不會構成重載)
    • 注意!區分值傳遞和引用傳遞

    • 示例

      package study1;
      
      public class a {
      
      	public static void main(String[] args) {
      		fun(1, 22, 31, 2, 44, 21, 98);
      		fun(new int[]{1, 22, 31, 2, 44, 21, 98});
      	}
      	
      	public static void fun(int... numbers){
              if (numbers.length == 0) {
                  System.out.println("No argument passed");
                  return;
              }
       
              int result = numbers[0];
       
              for (int i = 1; i <  numbers.length; i++){
                  if (numbers[i] >  result) {
                      result = numbers[i];
                  }
              }
              System.out.println("The max value is " + result);
      	}
      
      }
  • finalize 方法

    • Java 容許定義這樣的方法,它在對象被垃圾收集器析構(回收)以前調用,這個方法叫作 finalize( ),它用來清除回收對象。

    • 在 finalize() 方法裏,你必須指定在對象銷燬時候要執行的操做。

    • 固然,Java 的內存回收能夠由 JVM 來自動完成。若是你手動使用,則可使用上面的方法。

    • 該函數的通常格式

      protected void finalize() // 關鍵字 protected 是一個限定符,它確保 finalize() 方法不會被該類之外的代碼調用。
      {
         // 在這裏終結代碼
      }

方法調用

  • Java 支持兩種調用方法的方式,根據方法是否返回值來選擇。
  • 當程序調用一個方法時,程序的控制權交給了被調用的方法。當被調用方法的返回語句執行或者到達方法體閉括號時候交還控制權給程序。
  • 當方法返回一個值的時候,方法調用一般被當作一個值。
    • int larger = max(30, 40);
  • 若是方法返回值是void,方法調用必定是一條語句
    • System.out.println("Hello Java");

Tip:注意!在一些其它語言中方法指過程和函數。一個返回非void類型返回值的方法稱爲函數;一個返回void類型返回值的方法叫作過程。

方法重載

  • 一個類的兩個方法擁有相同的名字,可是有不一樣的參數列表。
  • Java編譯器根據方法簽名(方法名和參數列表)判斷哪一個方法應該被調用。
  • 方法重載可讓程序更清晰易讀。執行密切相關任務的方法應該使用相同的名字。
  • 重載的方法必須擁有不一樣的參數列表。你不能僅僅依據修飾符或者返回類型的不一樣來重載方法。
  • 規則:
    • 方法名稱必須相同。
    • 參數列表必須不一樣。
    • 方法的返回類型能夠相同也能夠不相同。
    • 僅僅返回類型不一樣不足以稱爲方法的重載。
  • 方法重載可能會由於沒有所知足的參數類型而出現自動的類型提高以便於調用適用的方法

遞歸

  • 一個方法在內部調用自身稱爲遞歸調用

  • 方法的遞歸包含了一種隱式的循環,他會重複指定某段代碼,可是這種循環執行無需循環的控制

  • 遞歸必定要已知方向遞歸(臨界條件),不然將會稱爲無窮遞歸(相似與死循環)

  • 簡單示例

    // 遞歸求和
    	public static int fun(int x){
    		if(x == 1){
    			return 1;
    		}else{
    			return x + fun(x - 1);
    		}
    	}

變量的做用域

  • 變量的範圍是程序中該變量能夠被引用的部分。

  • 方法內定義的變量被稱爲局部變量。

  • 局部變量的做用範圍從聲明開始,直到包含它的塊結束。

  • 局部變量必須聲明纔可使用。

  • 方法的參數範圍涵蓋整個方法。參數其實是一個局部變量。

  • for循環的初始化部分聲明的變量,其做用範圍在整個循環。

  • 但循環體內聲明的變量其適用範圍是從它聲明到循環體結束。它包含以下所示的變量聲明:

  • 你能夠在一個方法裏,不一樣的非嵌套塊中屢次聲明一個具備相同的名稱局部變量,但你不能在嵌套塊內兩次聲明局部變量。

Tip:命令行參數是在執行程序時候緊跟在程序名字後面的信息。

This

  • 指的是當前實例化的對象
  • 可使用調用當前類中的屬性或者方法(若方法中的形參與類中的屬性同名,則屬性必須使用this修飾) ,可是方法中的形參若不與屬性名相同則不建議加this
  • 在構造器中調用構造器this() ,根據傳入參數類型的不一樣而實現不一樣構造器的調用,且必須放置在構造器的首行
    • 不能在構造器內部調用本身
    • 僅能調用一個

封裝與隱藏

初識

Tip:程序設計的理念:高內聚,低耦合。

  • 在面向對象程式設計方法中,封裝(英語:Encapsulation)是指一種將抽象性函式接口的實現細節部分包裝、隱藏起來的方法。
  • 封裝能夠被認爲是一個保護屏障,防止該類的代碼和數據被外部類定義的代碼隨機訪問。
  • 要訪問該類的代碼和數據,必須經過嚴格的接口控制。
  • 封裝最主要的功能在於咱們能修改本身的實現代碼,而不用修改那些調用咱們代碼的程序片斷。
  • 適當的封裝可讓程式碼更容易理解與維護,也增強了程式碼的安全性。

封裝的優勢

  • 良好的封裝可以減小耦合。
  • 類內部的結構能夠自由修改。
  • 能夠對成員變量進行更精確的控制。
  • 隱藏信息,實現細節。

訪問控制

修飾符 當前類 同一包內 子孫類(同一包) 子孫類(不一樣包) 其餘包
public Y Y Y Y Y
protected Y Y Y Y/N N
default Y Y Y N N
private Y N N N N
  • default (即默認,什麼也不寫): 在同一包內可見,不使用任何修飾符。使用對象:類、接口、變量、方法。
    • 使用默認訪問修飾符聲明的變量和方法,對同一個包內的類是可見的。接口裏的變量都隱式聲明爲 public static final,而接口裏的方法默認狀況下訪問權限爲 public
  • private : 在同一類內可見。使用對象:變量、方法。 注意:不能修飾類(外部類)
    • 私有訪問修飾符是最嚴格的訪問級別,因此被聲明爲 private 的方法、變量和構造方法只能被所屬類訪問,而且類和接口不能聲明爲 private
    • 聲明爲私有訪問類型的變量只能經過類中公共的 getter 方法被外部類訪問。
    • Private 訪問修飾符的使用主要用來隱藏類的實現細節和保護類的數據。
  • public : 對全部類可見。使用對象:類、接口、變量、方法
    • 被聲明爲 public 的類、方法、構造方法和接口可以被任何其餘類訪問。
    • 若是幾個相互訪問的 public 類分佈在不一樣的包中,則須要導入相應 public 類所在的包。因爲類的繼承性,類全部的公有方法和變量都能被其子類繼承。
  • protected : 對同一包內的類和全部子類可見。使用對象:變量、方法。 注意:不能修飾類(外部類)
    • 子類與基類在同一包中:被聲明爲 protected 的變量、方法和構造器能被同一個包中的任何其餘類訪問;
    • 子類與基類不在同一包中:那麼在子類中,子類實例能夠訪問其從基類繼承而來的 protected 方法,而不能訪問基類實例的protected方法。
    • protected 能夠修飾數據成員,構造方法,方法成員,不能修飾類(內部類除外)。接口及接口的成員變量和成員方法不能聲明爲 protected。

Tip:構造器的訪問權限必定是小於該類的訪問權限(若構造器的訪問權限大於該類的訪問權限則是無效的)

方法繼承的規則

  • 父類中聲明爲 public 的方法在子類中也必須爲 public。
  • 父類中聲明爲 protected 的方法在子類中要麼聲明爲 protected,要麼聲明爲 public,不能聲明爲 private。
  • 父類中聲明爲 private 的方法,不可以被繼承。

JavaBean

  • 是一種Java語言寫成可重用組件
  • 所謂的JavaBean,是指以下標準的java類:
    • 是公共的
    • 有一個無參的公共的構造器
    • 有屬性而且有對應的get和set方法

package

  • 爲了更好地組織類,Java 提供了包機制,用於區別類名的命名空間,具體做用:
    • 把功能類似或相關的類或接口組織在同一個包中,方便類的查找和使用。
    • 如同文件夾同樣,包也採用了樹形目錄的存儲方式。同一個包中的類名字是不一樣的,不一樣的包中的類的名字是能夠相同的,當同時調用兩個不一樣包中相同類名的類時,應該加上包名加以區別。所以,包能夠避免名字衝突。
    • 包也限定了訪問權限,擁有包訪問權限的類才能訪問某個包中的類。
    • Java 使用包(package)這種機制是爲了防止命名衝突,訪問控制,提供搜索和定位類(class)、接口、枚舉(enumerations)和註釋(annotation)等。
  • 聲明格式:package pkg1[.pkg2[.pkg3…]]; (每 . 一次就表明一層文件目錄 )
    • 一個包(package)能夠定義爲一組相互聯繫的類型(類、接口、枚舉和註釋),爲這些類型提供訪問保護和命名空間管理的功能。
    • java.lang-打包基礎的類
    • java.io-包含輸入輸出功能的函數
  • 開發者能夠本身把一組類和接口等打包,並定義本身的包。並且在實際開發中這樣作是值得提倡的,當你本身完成類的實現以後,將相關的類分組,可讓其餘的編程者更容易地肯定哪些類、接口、枚舉和註釋等是相關的。
  • 因爲包建立了新的命名空間(namespace),因此不會跟其餘包中的任何名字產生命名衝突。使用包這種機制,更容易實現訪問控制,而且讓定位相關類更加簡單。
  • 聲明應該在源文件的第一行,每一個源文件只能有一個包聲明,這個文件中的每一個類型都應用於它。
  • 若是一個源文件中沒有使用包聲明,那麼其中的類,函數,枚舉,註釋等將被放在一個無名的包(unnamed package)中。
  • 類放在包中會有兩種主要的結果:
    • 包名成爲類名的一部分,正如咱們前面討論的同樣。
    • 包名必須與相應的字節碼所在的目錄結構相吻合。

import

  • 爲了可以使用某一個包的成員,咱們須要在 Java 程序中明確導入該包。使用 "import" 語句可完成此功能。
  • 在 java 源文件中 import 語句應位於 package 語句以後,全部類的定義以前,能夠沒有,也能夠有多條,其語法格式爲:import package1[.package2…].(classname|*);
  • 導入包中所有結構的通配符 * 可是,導入的內容不包括該包下的子包
  • 若是在一個包中,一個類想要使用本包中的另外一個類,那麼該包名能夠省略。
  • 類文件中能夠包含任意數量的 import 聲明。import 聲明必須在包聲明以後,類聲明以前。
  • 若是引入多個包中的類存在同名,則必須在使用時在相應的類前添加隸屬於包的標識(全類名),例如:xyz.patrickstar.com.Person
  • import static XXX :導入指定類或者接口中的靜態結構

Tip:類目錄的絕對路徑叫作 class path。設置在系統變量 CLASSPATH 中。編譯器和 java 虛擬機經過將 package 名字加到 class path 後來構造 .class 文件的路徑。一個 class path 可能會包含好幾個路徑,多路徑應該用分隔符分開。默認狀況下,編譯器和 JVM 查找當前目錄。JAR 文件按包含 Java 平臺相關的類,因此他們的目錄默認放在了 class path 中。

設置 CLASSPATH 系統變量

  • 用下面的命令顯示當前的CLASSPATH變量:

    • Windows 平臺(DOS 命令行下):C:> set CLASSPATH
    • UNIX 平臺(Bourne shell 下):# echo $CLASSPATH
  • 刪除當前CLASSPATH變量內容:

    • Windows 平臺(DOS 命令行下):C:> set CLASSPATH=
    • UNIX 平臺(Bourne shell 下):# unset CLASSPATH; export CLASSPATH
  • 設置CLASSPATH變量:

    • Windows 平臺(DOS 命令行下): C:> set CLASSPATH=C:\users\jack\java\classes
    • UNIX 平臺(Bourne shell 下):# CLASSPATH=/home/jack/java/classes; export CLASSPATH

MVC設計模式

簡介

  • MVC 模式表明 Model-View-Controller(模型-視圖-控制器) 模式。這種模式用於應用程序的分層開發。
    • Model(模型) - 模型表明一個存取數據的對象或 JAVA POJO。它也能夠帶有邏輯,在數據變化時更新控制器。
    • View(視圖) - 視圖表明模型包含的數據的可視化。
    • Controller(控制器) - 控制器做用於模型和視圖上。它控制數據流向模型對象,並在數據變化時更新視圖。它使視圖與模型分離開。

實現

  • 建立一個做爲模型的 Student 對象。StudentView 是一個把學生詳細信息輸出到控制檯的視圖類,StudentController 是負責存儲數據到 Student 對象中的控制器類,並相應地更新視圖 StudentView

  • MVCPatternDemo,演示類使用 StudentController 來演示 MVC 模式的用法。

繼承

基本概念

  • 繼承是java面向對象編程技術的一塊基石,由於它容許建立分等級層次的類。
  • 繼承就是子類繼承父類的特徵和行爲,使得子類對象(實例)具備父類的實例域和方法,或子類從父類繼承方法,使得子類具備父類相同的行爲。

基本使用

  • 格式:

    class 父類 {
    }
     
    class 子類 extends 父類 {
    }
  • 須要注意的是 Java 不支持多繼承,但支持多重繼承。

特性

  • 子類擁有父類全部的結構、屬性、方法。
    • private聲明的父類的屬性並不是不能繼承,若給其指定的屬性設置相應的get和set方法仍然能夠對其賦值和訪問(實質上在相應的對象中開闢了相應屬性的內存空間,只是由於封裝性的緣由而不能直接訪問)
  • 子類能夠擁有本身的屬性和方法,即子類能夠對父類進行擴展。
  • 子類能夠用本身的方式實現父類的方法。
  • 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具備多繼承的特性,使用範圍爲類繼承接口的狀況,能夠同時繼承多個接口(接口跟接口之間採用逗號分隔)。
  • super 與 this 關鍵字
    • super關鍵字:咱們能夠經過super關鍵字來實現對父類成員的訪問,用來引用當前對象的父類。
    • this關鍵字:指向本身的引用。
  • final關鍵字
    • final 關鍵字聲明類能夠把類定義爲不能繼承的,即最終類;或者用於修飾方法,該方法不能被子類重寫
    • 聲明類:final class 類名 {//類體}
    • 聲明方法:修飾符(public/private/default/protected) final 返回值類型 方法名(){//方法體}

Tip:注意!實例變量也能夠被定義爲 final,被定義爲 final 的變量不能被修改。被聲明爲 final 類的方法自動地聲明爲 final,可是實例變量並非 final

構造器

  • 子類是不繼承父類的構造器(構造方法或者構造函數)的,它只是調用(隱式或顯式)。若是父類的構造器帶有參數,則必須在子類的構造器中顯式地經過 super 關鍵字調用父類的構造器並配以適當的參數列表。

  • 若是父類構造器沒有參數,則在子類的構造器中不須要使用 super 關鍵字調用父類構造器,系統會自動調用父類的無參構造器。

相關文章
相關標籤/搜索