Java基礎概念、知識點整理

原文連接:https://foochane.cn/article/2...html

1 基礎概念

1.1 二進制

字節是計算機中最小存儲單元。計算機存儲任何的數據,都是以字節的形式存儲。8個bit(二進制位) 0000-0000表示爲1個字節,寫成1 byte或者1 B。java

  • 8 bit = 1 B
  • 1024 B =1 KB
  • 1024 KB =1 MB
  • 1024 MB =1 GB
  • 1024 GB = 1 TB

1.2 Java虛擬機

虛擬機是一種抽象化的計算機,經過在實際的計算機上仿真模擬各類計算機功能來實現的。Java虛擬機(Java Virtual Machine,JVM )有本身完善的硬體架構,如處理器、堆棧、寄存器等,還具備相應的指令系統。Java虛擬機屏蔽了與具體操做系統平臺相關的信息,使得Java程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就能夠在多種平臺上不加修改地運行。編程

所謂的java虛擬機,就是一臺虛擬的機器。它是一款軟件,用來執行一系列虛擬計算機指令,大致上虛擬機能夠分爲系統虛擬機和程序虛擬機。Visual Box、VMWare就屬於系統虛擬機。他們徹底是對物理計算機的仿真,提供一個可運行完整操做系統的軟件平臺。而java虛擬機就是典型程序虛擬機,它專門爲執行單個計算機程序而設計,在java虛擬機中執行的指令咱們稱之爲java字節碼指令。java發展到今天,出現了不少虛擬機,最初sun使用的叫Classic的java虛擬機,到如今使用最普遍的是HotSpot虛擬機,除了sun之外還有BEA的JRockit,目前JRockit和HotSpot都被甲骨文公司收入旗下,大有整合的趨勢。segmentfault

任何軟件的運行,都必需要運行在操做系統之上,而咱們用Java編寫的軟件能夠運行在任何的操做系
統上,這個特性稱爲Java語言的跨平臺特性。該特性是由JVM實現的,咱們編寫的程序運行在JVM上,而JVM運行在操做系統上。數組

1.3 JRE 和 JDK

  • JRE(Java Runtime Environment):是Java程序的運行時環境,包含 JVM 和運行時所須要的 核心類庫 。
  • JDK(Java Development Kit):是Java程序開發工具包,包含 JRE 和開發人員使用的工具。

咱們想要運行一個已有的Java程序,那麼只需安裝 JRE 便可。咱們想要開發一個全新的Java程序,那麼必須安裝 JDK 。安全

1.4 常量和變量

  • 常量:程序運行中固定不變的量
  • 變量:程序中運行能夠變化的量

常量分類:架構

類型 含義 舉例
整數常量 全部的整數 0,1, 567, -9
小數常量 全部的小數 0.0, -0.1, 2.55
字符常量 單引號引發來,只能寫一個字符,必須有內容 'a' , ' ', '好'
字符串常量 雙引號引發來,能夠寫多個字符,也能夠不寫 "A" ,"Hello" ,"你好" ,""
布爾常量 只有兩個值 true , false
空常量 只有一個值 null

變量分類:編程語言

Java的數據類型分爲兩大類:ide

  • 基本數據類型 :整數 、 浮點數 、 字符 、 布爾 。
  • 引用數據類型 :類 、 數組 、 接口 。
數據類型 關鍵字 佔用內存 取值範圍
字節型 byte 1個字節 -128~127
短整型 short 2個字節 -32768~32767
整型 int(默認) 4個字節 $-2^{31}$~$2^{31}-1$
長整型 long 8個字節 $-2^{63}$~$2^{63}-1$
單精度浮點數 float 4個字節 1.4013E-45~3.4028E+38
雙精度浮點數 double(默認) 8個字節 4.9E-324~1.7977E+308
字符型 char 2個字節 0-65535
布爾類型 boolean 1個字節 true,false
long類型:建議數據後加 L表示
float類型:建議數據後加 F表示

1.5 數據類型轉換

自動類型轉換(隱式)函數

  • 特色:代碼不須要進行特殊處理,自動完成。
  • 規則:數據範圍從小到大。

強制類型轉換(顯式)

  • 特色:代碼須要進行特殊的格式處理,不能自動完成。
  • 格式:範圍小的類型 範圍小的變量名 =(範圍小的類型) 本來範圍大的數據;

注意事項:

  1. 強制類型轉換通常不推薦使用,由於有可能發生精度損失、數據溢出。
  2. byte/short/char這三種類型均可以發生數學運算,例如加法「+」.
  3. byte/short/char這三種類型在運算的時候,都會被首先提高成爲int類型,而後再計算。
  4. boolean類型不能發生數據類型轉換

1.6 運算符

算數運算符

符號 說明
+ 加法運算,字符串鏈接運算
- 減法運算
* 乘法運算
/ 除法運算
% 取模運算,兩個數字相除取餘數
++ 、 -- 自增自減運算

前++和後++的區別

public static void main(String[] args) {
    int a = 1;
    int b = ++a;
    System.out.println(a);//計算結果是2
    System.out.println(b);//計算結果是2
}
public static void main(String[] args) {
    int a = 1;
    int b = a++;
    System.out.println(a);//計算結果是2
    System.out.println(b);//計算結果是1
}

賦值運算符

符號 說明
= 等於號
+= 加等於
- = 減等於
*= 乘等於
/= 除等於
%= 取模等

比較運算符

符號 說明
== 比較符號兩邊數據是否相等,相等結果是true。
< 比較符號左邊的數據是否小於右邊的數據,若是小於結果是true。
> 比較符號左邊的數據是否大於右邊的數據,若是大於結果是true。
<= 比較符號左邊的數據是否小於或者等於右邊的數據,若是小於結果是true。
>= 比較符號左邊的數據是否大於或者等於右邊的數據,若是小於結果是true。
! = 不等於符號 ,若是符號兩邊的數據不相等,結果是true。

邏輯運算符

符號 說明
&& 短路與 1. 兩邊都是true,結果是true<br/>2. 一邊是false,結果是false<br/>短路特色:符號左邊是false,右邊再也不運算
\ \ 短路或 1. 兩邊都是false,結果是false<br/>2. 一邊是true,結果是true<br/>短路特色: 符號左邊是true,右邊再也不運算
! 取反 1. ! true 結果是false<br/>2. ! false結果是true

三元運算符

三元運算符格式:

數據類型 變量名 = 布爾類型表達式?結果1:結果2

示例:

public static void main(String[] args) {
    int i = (1==2 ? 100 : 200);
    System.out.println(i);//200
    int j = (3<=4 ? 500 : 600);
    System.out.println(j);//500
}

1.7 JShell腳本工具

JShell腳本工具是JDK9的新特性,當咱們編寫的代碼很是少的時候,而又不肯意編寫類,main方法,也不肯意去編譯和運行,這個時候可使用JShell工具。

啓動JShell工具,在DOS命令行直接輸入JShell命令。

1.8 IDEA快捷鍵

快捷鍵 功能
Alt + Enter 導入包,自動代碼修正
Ctrl+Y 刪除光標所在行
Ctrl+D 複製光標所在行的內容,插入光標位置下面
Ctrl+Alt+L 格式化代碼
Ctrl+/ 單行註釋
Ctrl+Shift+/ 選中代碼註釋,多行註釋,再按取消註釋
Alt+Ins 自動生成代碼,toString,get,set等方法
Alt+Shift+ 上下箭頭 移動當前代碼行
Shift+F6 同時修改不一樣地方的同一個量
輸入sout System.out.println();
輸入psvm public static void main(String[] args)
輸入5.fori for(int i = 0; i < 5; i++)
輸入arr.fori或者arr.forr for循環變量數組

2 流程控制語句

2.1 判斷語句if-else

語句格式:

if (判斷條件1) {
   執行語句1;  
} else if (判斷條件2) {
   執行語句2;  
}
...
}else if (判斷條件n) {
  執行語句n;   
} else {
   執行語句n+1;  
}

2.2 選擇語句swich-case

語句格式:

switch(表達式) {
  case 常量值1:
    語句體1;
    break;
  case 常量值2:
    語句體2;
    break;
  ...
  default:
    語句體n+1;
    break;
}

2.3 循環語句

循環語句for

語句格式:

for(初始化表達式①; 布爾表達式②; 步進表達式④){
循環體③        
}

執行流程
執行順序:①②③④ >②③④>②③④…②不知足爲止。
①負責完成循環變量初始化
②負責判斷是否知足循環條件,不知足則跳出循環
③具體執行的語句
④循環後,循環條件所涉及變量的變化狀況

循環語句while

語句格式1:

初始化表達式①
  while(布爾表達式②){
    循環體③
    步進表達式④
}

執行流程
執行順序:①②③④ >②③④>②③④…②不知足爲止。
①負責完成循環變量初始化。
②負責判斷是否知足循環條件,不知足則跳出循環。
③具體執行的語句。
④循環後,循環變量的變化狀況。

語句格式2:

初始化表達式①
    do{
    循環體③
    步進表達式④
}while(布爾表達式②);

執行流程
執行順序:①③④ >②③④>②③④…②不知足爲止。
①負責完成循環變量初始化。
②負責判斷是否知足循環條件,不知足則跳出循環。
③具體執行的語句
④循環後,循環變量的變化狀況

2.4 break和continue

break

使用場景:終止 switch或者循環

  • 在選擇結構 switch語句中
  • 在循環語句中
  • 離開使用場景的存在是沒有意義的

示例:

public static void main(String[] args) {
    for (int i = 1; i<=10; i++) {
        //需求:打印完兩次HelloWorld以後結束循環
        if(i == 3){
          break;
        }
        System.out.println("HelloWorld"+i);
    }
}

continue

使用場景:結束本次循環,繼續下一次的循環

示例:

public static void main(String[] args) {
    for (int i = 1; i <= 10; i++) {
        //需求:不打印第三次HelloWorld
        if(i == 3){
          continue;
        }
        System.out.println("HelloWorld"+i);
    }
}

3 數組

3.1 容器

容器: 是將多個數據存儲到一塊兒,每一個數據稱爲該容器的元素。

3.2 數組概念

數組概念: 數組就是存儲數據長度固定的容器,保證多個數據的數據類型要一致。

3.3 數組的定義

方式一

格式:

數組存儲的數據類型[] 數組名字 = new 數組存儲的數據類型[長度];

示例:

int[] arr = new int[3];

方式二

格式:

數據類型[] 數組名 = new 數據類型[]{元素1,元素2,元素3...};

示例:

int[] arr = new int[]{1,2,3,4,5};

方式三

格式:

數據類型[] 數組名 = {元素1,元素2,元素3...};

示例:

int[] arr = {1,2,3,4,5};

【注意】:

  1. 數組有定長特性,長度一旦指定,不可更改
  2. 方式三一樣也進行了new操做

3.4 數組操做

  • 索引: 每個存儲到數組的元素,都會自動的擁有一個編號,從0開始,這個自動編號稱爲數組索引(index),能夠經過數組的索引訪問到數組中的元素。
  • 數組的長度: 每一個數組都具備長度,並且是固定的,Java中賦予了數組的一個屬性,能夠獲取到數組的長度,語句爲: 數組名 .length ,屬性length的執行結果是數組的長度,int類型結果。由次能夠推斷出,數組的最大索引值爲 數組名 .length-1
  • 索引訪問數組中的元素: 數組名[索引]

示例:

public static void main(String[] args) {
    //定義存儲int類型數組,賦值元素1,2,3,4,5
    int[] arr = {1,2,3,4,5};
    //爲0索引元素賦值爲6
    arr[0] = 6;
    //獲取數組0索引上的元素
    int i = arr[0];
    System.out.println(i);
    //直接輸出數組0索引元素
    System.out.println(arr[0]);
}

數組取最大值

代碼以下:

public static void main(String[] args) {
    int[] arr = { 5, 15, 2000, 10000, 100, 4000 };
    //定義變量,保存數組中0索引的元素
    int max = arr[0];
    //遍歷數組,取出每一個元素
    for (int i = 0; i < arr.length; i++) {
      //遍歷到的元素和變量max比較
      //若是數組元素大於max
      if (arr[i] > max) {
        //max記錄住大值
        max = arr[i];
      }
    }
    System.out.println("數組最大值是: " + max);
}

數組反轉

代碼以下:

public static void main(String[] args) {
    int[] arr = { 1, 2, 3, 4, 5 };
    /*
      循環中定義變量min=0最小索引
      max=arr.length‐1最大索引
      min++,max‐‐
      */
    for (int min = 0, max = arr.length ‐ 1; min <= max; min++, max‐‐) {
      //利用第三方變量完成數組中的元素交換
      int temp = arr[min];
      arr[min] = arr[max];
      arr[max] = temp;
    }
    // 反轉後,遍歷數組
    for (int i = 0; i < arr.length; i++) {
      System.out.println(arr[i]);
    }
}

3.5 數組內存劃分

內存是計算機中的重要原件,臨時存儲區域,做用是運行程序。咱們編寫的程序是存放在硬盤中的,在硬盤中的程序是不會運行的,必須放進內存中才能運行,運行完畢後會清空內存。

Java虛擬機要運行程序,必需要對內存進行空間的分配和管理。

Java的內存須要劃分紅爲5個部分:

  1. 棧(Stack) :存放的都是方法中的局部變量。方法的運行必定要在棧當中運行。

    • 局部變量:方法的參數,或者是方法{}內部的變量
    • 做用域:一旦超出做用域,馬上從棧內存當中消失。
  2. 堆(Heap):凡是new出來的東西,都在堆當中。

    • 堆內存裏面的東西都有一一個地址值: 16進制
    • 堆內存裏面的數據,都有默認值。規則:

      • 若是是整數 默認爲0
      • 若是是浮點數 默認爲0.0
      • 若是是字符 默認爲'\u0000'
      • 若是是布爾 默認爲false
      • 若是是引用類型 默認爲null
  3. 方法區(Method Area):存儲class相關信息,包含方法的信息。
  4. 本地方法棧(Native Method Stack):與操做系統相關。
  5. 寄存器(PC Register) :與CPU相關。

示例:

public static void main(String[] args) {
    
    // 定義數組,存儲3個元素
    int[] arr = new int[3];
    
    //數組索引進行賦值
    arr[0] = 5;
    arr[1] = 6;
    arr[2] = 7;
    
    //輸出3個索引上的元素值
    System.out.println(arr[0]);
    System.out.println(arr[1]);
    System.out.println(arr[2]);

}

代碼執行流程:

  1. main方法進入方法棧。程序運行前main方法存儲在方法區,程序運行時,main方法進入棧
  2. 建立數組。JVM在堆內存中開闢一個內存空間存儲數組(new int[3]),數組中的三個元素默認值爲0。內存地址以一個十六進制數表示(0xff343)。
  3. JVM將內存地址賦值給變量 arr。變量arr保存的是數組內存中的地址,而不是一個具體的數值,所以數組爲引用數據類型。
  4. 根據數組索引給數組的3個元素賦值,分佈賦值爲5,6,7。而後進行打印。

數組內存圖

兩個變量指向同一個數據:

public static void main(String[] args) {
    // 定義數組,存儲3個元素
    int[] arr = new int[3];
    //數組索引進行賦值
    arr[0] = 5;
    arr[1] = 6;
    arr[2] = 7;
    //輸出3個索引上的元素值
    System.out.println(arr[0]);
    System.out.println(arr[1]);
    System.out.println(arr[2]);
    //定義數組變量arr2,將arr的地址賦值給arr2
    int[] arr2 = arr;
    arr2[1] = 9;
    System.out.println(arr[1]);
}

上述代碼中,arr和arr2都指向同一個內存地址,arr2[1] = 9執行後,arr[1]也會跟着改變。

4 面向對象

Java語言是一種面向對象的程序設計語言,而面向對象思想是一種程序設計思想,咱們在面向對象思想的指引下,
使用Java語言去設計、開發計算機程序。 這裏的對象泛指現實中一切事物,每種事物都具有本身的屬性和行爲。面向對象思想就是在計算機程序設計過程當中,參照現實中事物,將事物的屬性特徵、行爲特徵抽象出來,描述成計算機事件的設計思想。 它區別於面向過程思想,強調的是經過調用對象的行爲來實現功能,而不是本身一步一步的去操做實現。

面向對象思想是一種更符合咱們思考習慣的思想,它能夠將複雜的事情簡單化,並將咱們從執行者變成了指揮者。面向對象的語言中,包含了三大基本特徵,即封裝、繼承和多態。

4.1 類和對象

  • 類 :是一組相關屬性行爲的集合。能夠當作是一類事物的模板,使用事物的屬性特徵和行爲特徵來描述該
    類事物。

    • 屬性:事物的狀態信息。
    • 行爲:事物可以作什麼。
  • 對象 :是一類事物的具體體現。對象是類的一個實例,必然具有該類事物的屬性和行爲。
  • 類與對象的關係

    • 類是對一類事物的描述,是 抽象的。
    • 對象是一類事物的實例,是 具體的。
    • 類是對象的模板,對象是類的實體 。

4.2 類的定義

定義格式:

public class ClassName {
  //成員變量
  //成員方法
}

示例:

public class Student {
   //成員變量  
   String name;//姓名  
   int age;//年齡
   
   //成員方法
   //學習的方法
    public void study() {
    System.out.println("好好學習,每天向上");
  }
  //吃飯的方法
  publicvoid eat() {
    System.out.println("學習餓了要吃飯");
  }
}

4.3 對象使用

對象的使用格式

建立對象:

類名 對象名 = new 類名();

使用對象訪問類中的成員:

對象名.成員變量;
對象名.成員方法();

示例:

public class Test01_Student {
  public static void main(String[] args) {
    //建立對象格式:類名 對象名 = new 類名();
    Student s = new Student();
    System.out.println("s:"+s); //cn.itcast.Student@100363
    //直接輸出成員變量值
    System.out.println("姓名:"+s.name); //null
    System.out.println("年齡:"+s.age); //0
    System.out.println("‐‐‐‐‐‐‐‐‐‐");
    //給成員變量賦值
    s.name = "趙麗穎";
    s.age = 18;
    //再次輸出成員變量的值
    System.out.println("姓名:"+s.name); //趙麗穎
    System.out.println("年齡:"+s.age); //18
    System.out.println("‐‐‐‐‐‐‐‐‐‐");
    //調用成員方法
    s.study(); // "好好學習,每天向上"
    s.eat(); // "學習餓了要吃飯"
  }
}

成員變量的默認值

  • 基本類型:

    • 整數(byte,short,int,long):0
    • 浮點數(float,double):0.0
    • 字符(char): '\u0000'
    • 布爾(boolean):false

      • 引用類型:數組,類,接口 null

4.4 成員變量和局部變量區別

public class Car{
    String color; //成員變量
    public void drive(){
        int speed = 80; //局部變量
        //......
    }
}
  • 在類中的位置不一樣

    • 成員變量:類中,方法外
    • 局部變量:方法中或者方法聲明上(形式參數)
  • 做用範圍不同

    • 成員變量:類中
    • 局部變量:方法中
  • 初始化值的不一樣

    • 成員變量:有默認值
    • 局部變量:沒有默認值。必須先定義,賦值,最後使用在內
  • 存中的位置不一樣

    • 成員變量:堆內存
    • 局部變量:棧內存
  • 生命週期不一樣

    • 成員變量:隨着對象的建立而存在,隨着對象的消失而消失
    • 局部變量:隨着方法的調用而存在,隨着方法的調用完畢而消失

5 封裝

面向對象編程語言是對客觀世界的模擬,客觀世界裏成員變量都是隱藏在對象內部的,外界沒法直接操做和修改。封裝能夠被認爲是一個保護屏障,防止該類的代碼和數據被其餘類隨意訪問。要訪問該類的數據,必須經過指定的方式。適當的封裝可讓代碼更容易理解與維護,也增強了代碼的安全性。

封裝的步驟

  1. 使用 private 關鍵字來修飾成員變量。
  2. 對須要訪問的成員變量,提供對應的一對 getXxx 方法 、 setXxx 方法。

5.1 private關鍵字

private的含義

  1. private是一個權限修飾符,表明最小權限。
  2. 能夠修飾成員變量和成員方法。
  3. private修飾後的成員變量和成員方法,只在本類中才能訪問。

private的使用格式:

private 數據類型 變量名;
  1. 使用 private 修飾成員變量,代碼以下:
public class Student {
  private String name;
  private int age;
}
  1. 提供 getXxx 方法 / setXxx 方法,能夠訪問成員變量,代碼以下:
public class Student {
  private String name;
  private int age;
  public void setName(String n) {
    name = n;
  }
  public String getName() {
    return name;
  }
  public void setAge(int a) {
    age = a;
  }
  public int getAge() {
    return age;
  }
}

5.2 this關鍵字

this的含義this表明所在類的當前對象的引用(地址值),即對象本身的引用。

方法被哪一個對象調用,方法中的this就表明那個對象。即誰在調用,this就表明誰。

this使用格式:

this.成員變量名;

使用 this 修飾方法中的變量,解決成員變量被隱藏的問題,代碼以下:

因爲形參變量名與成員變量名重名,致使成員變量名被隱藏,方法中的變量名,沒法訪問到成員變量,從而賦值失敗。因此,咱們只能使用this關鍵字,來解決這個重名問題。
public class Student {
  private String name;
  private int age;
  public void setName(String name) {
    //name = name;
    this.name = name;
  }
  public String getName() {
    return name;
  }
  public void setAge(int age) {
    //age = age;
    this.age = age;
  }
  public int getAge() {
    return age;
  }

5.3 構造方法

當一個對象被建立時候,構造方法用來初始化該對象,給對象的成員變量賦初始值。

不管你與否自定義構造方法,全部的類都有構造方法,由於Java自動提供了一個無參數構造方法,一旦本身定義了構造方法,Java自動提供的默認無參數構造方法就會失效。

構造方法的定義格式:

修飾符 構造方法名(參數列表){
// 方法體    
}

構造方法的寫法上,方法名與它所在的類名相同。它沒有返回值,因此不須要返回值類型,甚至不須要void。使用構造方法後,代碼以下:

public class Student {
  private String name;
  private int age;
  // 無參數構造方法
  public Student() {}
  // 有參數構造方法
  public Student(String name,int age) {
    this.name = name;
    this.age = age;
  }
}

注意事項

  1. 若是你不提供構造方法,系統會給出無參數構造方法。
  2. 若是你提供了構造方法,系統將再也不提供無參數構造方法。
  3. 構造方法是能夠重載的,既能夠定義參數,也能夠不定義參數。

5.4 JavaBean

JavaBean 是 Java語言編寫類的一種標準規範。符合 JavaBean 的類,要求類必須是具體的和公共的,而且具備無參數的構造方法,提供用來操做成員變量的 set 和 get 方法。

public class ClassName{
  //成員變量
  //構造方法
  //無參構造方法【必須】
  //有參構造方法【建議】
  //成員方法   
  //getXxx()
  //setXxx()
}

編寫符合 JavaBean 規範的類,以學生類爲例,標準代碼以下:

public class Student {
  //成員變量
  private String name;
  private int age;
  //構造方法
  public Student() {}
  public Student(String name,int age) {
    this.name = name;
    this.age = age;
  }
  //成員方法
  publicvoid setName(String name) {
    this.name = name;
  }
  public String getName() {
    return name;
  }
  publicvoid setAge(int age) {
    this.age = age;
  }
  publicint getAge() {
    return age;
  }
}

6 繼承

多個類中存在相同屬性和行爲時,將這些內容抽取到單獨一個類中,那麼多個類無需再定義這些屬性和行爲,只要繼承那一個類便可。

其中,多個類能夠稱爲子類,單獨那一個類稱爲父類、超類(superclass)或者基類。

父類更通用,子類更具體。咱們經過繼承,可使多種事物之間造成一種關係體系。

6.1 定義

繼承 :就是子類繼承父類的屬性和行爲,使得子類對象具備與父類相同的屬性、相同的行爲。子類能夠直接訪問父類中的非私有的屬性和行爲。

好處:

  1. 提升代碼的複用性。
  2. 類與類之間產生了關係,是多態的前提。

格式:

經過 extends 關鍵字,能夠聲明一個子類繼承另一個父類,定義格式以下:

class 父類 {
...    
}
class 子類 extends 父類 {
...    
}

示例:

/*
 * 定義員工類Employee,作爲父類
 */
class Employee {
String name; // 定義name屬性    
// 定義員工的工做方法    
public void work() {    
System.out.println("全力以赴地工做");        
}    
}
/*
 * 定義講師類Teacher 繼承 員工類Employee
 */
class Teacher extends Employee {
// 定義一個打印name的方法    
public void printName() {    
System.out.println("name=" + name);        
}    
}
/*
 * 定義測試類
 */
public class ExtendDemo01 {
public static void main(String[] args) {    
        // 建立一個講師類對象
Teacher t = new Teacher();        
     
        // 爲該員工類的name屬性進行賦值
t.name = "小明";         
     
       // 調用該員工的printName()方法  
t.printName(); // name = 小明        
       
       // 調用Teacher類繼承來的work()方法  
       t.work();  // 全力以赴地工做  
}    
}

6.2 繼承後的特色

成員變量

  • 成員變量不重名

    • 若是子類父類中出現不重名的成員變量,這時的訪問是沒有影響的。
  • 成員變量重名

    • 若是子類父類中出現重名的成員變量,這時的訪問是有影響的。
    • 子父類中出現了同名的成員變量時,在子類中須要訪問父類中非私有成員變量時,須要使用 super 關鍵字,修飾父類成員變量,相似於以前學過的 this

成員方法

  • 成員方法不重名

    • 若是子類父類中出現不重名的成員方法,這時的調用是沒有影響的。
    • 對象調用方法時,會先在子類中查找有沒有對應的方法,若子類中存在就會執行子類中的方法,若子類中不存在就會執行父類中相應的方法。
  • 成員方法重名 ——重寫(Override)

    • 若是子類父類中出現重名的成員方法,這時的訪問是一種特殊狀況,叫作方法重寫(Override)。

構造方法

  • 構造方法的名字是與類名一致的。因此子類是沒法繼承父類構造方法的。
  • 構造方法的做用是初始化成員變量的。因此子類的初始化過程當中,必須先執行父類的初始化動做。子類的構造方法中默認有一個 super() ,表示調用父類的構造方法,父類成員變量初始化後,才能夠給子類使用。
class Fu {
  private int n;
  Fu(){
    System.out.println("Fu()");
  }
}

class Zi extends Fu {
  Zi(){
    // super(),調用父類構造方法
    super();
    System.out.println("Zi()");
  } 
}
public class ExtendsDemo07{
  public static void main (String args[]){
    Zi zi = new Zi();
  }
}
輸出結果:
Fu()
Zi()

Java繼承特色

Java只支持單繼承,不支持多繼承。

6.3 重寫(Override)

方法重寫 :子類中出現與父類如出一轍的方法時(返回值類型,方法名和參數列表都相同),會出現覆蓋效果,也稱爲重寫或者複寫。聲明不變,從新實現。

示例:

子類能夠根據須要,定義特定於本身的行爲。既沿襲了父類的功能名稱,又根據子類的須要從新實現父類方法,從而進行擴展加強。好比新的手機增長來電顯示頭像的功能,代碼以下:

class Phone {
    public void sendMessage(){    
        System.out.println("發短信");        
    }    
    public void call(){    
        System.out.println("打電話");        
    }    
    public void showNum(){    
        System.out.println("來電顯示號碼");        
    }    
}

//智能手機類
class NewPhone extends Phone {
   
    //重寫父類的來電顯示號碼功能,並增長本身的顯示姓名和圖片功能    
    public void showNum(){    
        //調用父類已經存在的功能使用super        
        super.showNum();        
        //增長本身特有顯示姓名和圖片功能        
        System.out.println("顯示來電姓名");        
        System.out.println("顯示頭像");        
    }    
}
public class ExtendsDemo06 {
public static void main(String[] args) {    
       // 建立子類對象  
       NewPhone np = new NewPhone();  
       
        // 調用父類繼承而來的方法
        np.call();
     
       // 調用子類重寫的方法  
       np.showNum();  
}    
}

注意事項

  1. 子類方法覆蓋父類方法,必需要保證權限大於等於父類權限。
  2. 子類方法覆蓋父類方法,返回值類型、函數名和參數列表都要如出一轍。

6.4 super 和this

父類空間優先於子類對象產生

在每次建立子類對象時,先初始化父類空間,再建立其子類對象自己。目的在於子類對象中包含了其對應的父類空間,即可以包含其父類的成員,若是父類成員非private修飾,則子類能夠隨意使用父類成員。代碼體如今子類的構造方法調用時,必定先調用父類的構造方法。

super和this的含義

  • super :表明父類的存儲空間標識(能夠理解爲父親的引用)。
  • this :表明當前對象的引用(誰調用就表明誰)。

super和this的用法

  1. 訪問成員
this.成員變量     ‐‐    本類的   
super.成員變量     ‐‐    父類的  
this.成員方法名()   ‐‐    本類的      
super.成員方法名()   ‐‐    父類的

示例:

class Animal {
    public void eat() {
        System.out.println("animal : eat");
    }
}
class Cat extends Animal {
    public void eat() {
        System.out.println("cat : eat");
    }
    public void eatTest() {
        this.eat();   // this  調用本類的方法
        super.eat();  // super 調用父類的方法
    }
}
public class ExtendsDemo {
    public static void main(String[] args) {
        Animal a = new Animal();
        a.eat();
        Cat c = new Cat();
        c.eatTest();
    }
}
輸出結果爲:
animal : eat
cat : eat
animal : eat
  1. 訪問構造方法
this(...)     ‐‐    本類的構造方法   
super(...)    ‐‐    父類的構造方法
  • 子類的每一個構造方法中均有默認的super(),調用父類的空參構造。手動調用父類構造會覆蓋默認的super()。
  • super() 和 this() 都必須是在構造方法的第一行,因此不能同時出現。

6.5 抽象類-abstract

父類中的方法,被它的子類們重寫,子類各自的實現都不盡相同。那麼父類的方法聲明和方法主體,只有聲明還有意義,而方法主體則沒有存在的意義了。咱們把沒有方法主體的方法稱爲抽象方法Java語法規定,包含抽象方法的類就是抽象類

抽象方法 : 沒有方法體的方法。

使用 abstract 關鍵字修飾方法,該方法就成了抽象方法,抽象方法只包含一個方法名,而沒有方法體

格式:

修飾符 abstract 返回值類型 方法名 (參數列表);

示例:

public abstract void run();

抽象類 :包含抽象方法的類。

格式:

abstract class 類名字 {
 
}

示例:

public abstract class Animal {
    public abstract void run();
}

抽象的使用:

繼承抽象類的子類必須重寫父類全部的抽象方法。不然,該子類也必須聲明爲抽象類。最終,必須有子類實現該父類的抽象方法,不然,從最初的父類到最終的子類都不能建立對象,失去意義。

public class Cat extends Animal {
    public void run (){
       System.out.println("小貓在牆頭走~~~");         
    }
}
public class CatTest {
   public static void main(String[] args) {   
        // 建立子類對象
        Cat c = new Cat();
      
        // 調用run方法
        c.run();
   }  
}
輸出結果:
小貓在牆頭走~~~

此時的方法重寫,是子類對父類抽象方法的完成實現,咱們將這種方法重寫的操做,也叫作實現方法。

7 多態

多態 : 是指同一行爲,具備多個不一樣表現形式。

7.1 多態的體現

多態體現的格式:

父類類型 變量名 = new 子類對象; //父類類型:指子類對象繼承的父類類型,或者實現的父接口類型。
變量名.方法名();

當使用多態方式調用方法時,首先檢查父類中是否有該方法,若是沒有,則編譯錯誤;若是有,執行的是子類重寫後方法。

定義父類:

public abstract class Animal { 
    public abstract void eat(); 
}

定義子類:

class Cat extends Animal { 
    public void eat() { 
        System.out.println("吃魚"); 
    } 
} 
class Dog extends Animal { 
    public void eat() { 
        System.out.println("吃骨頭"); 
    } 
}

定義測試類:

public class Test {
    public static void main(String[] args) {
        // 多態形式,建立對象
        Animal a1 = new Cat(); 
        // 調用的是 Cat 的 eat
        a1.eat();         
        // 多態形式,建立對象
        Animal a2 = new Dog();
        // 調用的是 Dog 的 eat
        a2.eat();              
    } 
}

7.2 多態的好處

實際開發的過程當中,父類類型做爲方法形式參數,傳遞子類對象給方法,進行方法的調用,更能體現出多態的擴展性與便利。

定義父類:

public abstract class Animal { 
    public abstract void eat(); 
} 

定義子類:

class Cat extends Animal { 
    public void eat() { 
        System.out.println("吃魚"); 
    } 
} 
class Dog extends Animal { 
    public void eat() { 
        System.out.println("吃骨頭"); 
    } 
}

定義測試類:

public class Test {
    public static void main(String[] args) {
        // 多態形式,建立對象
        Cat c = new Cat(); 
        Dog d = new Dog();
        // 調用showCatEat
        showCatEat(c);
        // 調用showDogEat
        showDogEat(d);
        /*
        以上兩個方法, 都可以被showAnimalEat(Animal a)方法所替代
        而執行效果一致
        */
        showAnimalEat(c);
        showAnimalEat(d);
    }
    public static void showCatEat (Cat c){
        c.eat();
    }
    public static void showDogEat (Dog d){
        d.eat();
    }
    public static void showAnimalEat (Animal a){
        a.eat();
    }
}

因爲多態特性的支持, showAnimalEat方法的Animal類型,是Cat和Dog的父類類型,父類類型接收子類對象,固然能夠把Cat對象和Dog對象,傳遞給方法。

當eat方法執行時,多態規定,執行的是子類重寫的方法,那麼效果天然與showCatEat、showDogEat方法一致,因此showAnimalEat徹底能夠替代以上兩方法。

不只僅是替代,在擴展性方面,不管以後再多的子類出現,咱們都不須要編寫showXxxEat方法了,直接使用showAnimalEat均可以完成。

因此,多態的好處,體如今,可使程序編寫的更簡單,並有良好的擴展。

7.3 引用類型轉換

多態的轉型分爲向上轉型與向下轉型兩種

向上轉型

向上轉型 :多態自己是子類類型向父類類型向上轉換的過程,這個過程是默認的。當父類引用指向一個子類對象時,即是向上轉型。

使用格式:

父類類型  變量名 = new 子類類型();
如:Animal a = new Cat();

向下轉型

向下轉型 :父類類型向子類類型向下轉換的過程,這個過程是強制的。一個已經向上轉型的子類對象,將父類引用轉爲子類引用,可使用強制類型轉換的格式,即是向下轉型。

使用格式:

子類類型 變量名 = (子類類型) 父類變量名;
如:Cat c =(Cat) a; 

爲何要轉型

當使用多態方式調用方法時,首先檢查父類中是否有該方法,若是沒有,則編譯錯誤。也就是說,不能調用子類擁有,而父類沒有的方法。編譯都錯誤,更別說運行了。這也是多態給咱們帶來的一點"小麻煩"。因此,想要調用子類特有的方法,必須作向下轉型。

轉型演示,代碼以下:

定義類:

abstract class Animal { 
    abstract void eat(); 
} 
class Cat extends Animal { 
    public void eat() { 
        System.out.println("吃魚"); 
    } 
    public void catchMouse() { 
        System.out.println("抓老鼠"); 
    } 
} 
class Dog extends Animal { 
    public void eat() { 
        System.out.println("吃骨頭"); 
    } 
    public void watchHouse() { 
        System.out.println("看家"); 
    } 
}

定義測試類:

public class Test {
    public static void main(String[] args) {
        // 向上轉型 
        Animal a = new Cat(); 
        a.eat();  // 調用的是 Cat 的 eat               
        // 向下轉型 
        Cat c = (Cat)a;      
        c.catchMouse();  // 調用的是 Cat 的 catchMouse        
    } 
}

轉型的異常

轉型的過程當中,一不當心就會遇到這樣的問題,請看以下代碼:

public class Test {
    public static void main(String[] args) {
        // 向上轉型 
        Animal a = new Cat(); 
        a.eat();               // 調用的是 Cat 的 eat
        // 向下轉型 
        Dog d = (Dog)a;      
        d.watchHouse();        // 調用的是 Dog 的 watchHouse 【運行報錯】
    } 
}

這段代碼能夠經過編譯,可是運行時,卻報出了 ClassCastException ,類型轉換異常!這是由於,明明建立了Cat類型對象,運行時,固然不能轉換成Dog對象的。這兩個類型並無任何繼承關係,不符合類型轉換的定義。

爲了不ClassCastException的發生,Java提供了 instanceof 關鍵字,給引用變量作類型的校驗,格式以下:

變量名 instanceof 數據類型
若是變量屬於該數據類型,返回true。
若是變量不屬於該數據類型,返回false。

因此,轉換前,咱們最好先作一個判斷,代碼以下:

public class Test {
    public static void main(String[] args) {
        // 向上轉型 
        Animal a = new Cat(); 
        a.eat();               // 調用的是 Cat 的 eat
        // 向下轉型 
        if (a instanceof Cat){
            Cat c = (Cat)a;      
            c.catchMouse();        // 調用的是 Cat 的 catchMouse
        } else if (a instanceof Dog){
            Dog d = (Dog)a;      
            d.watchHouse();       // 調用的是 Dog 的 watchHouse
        }
    } 
}
相關文章
相關標籤/搜索