前面,我們講了Java中的一些基本的特征,與其他語言也有很多的相似之處,本期文章,我們來看一看在Java中包的概念和繼承的概念,大家坐好,我們發車了!!!

前期文章:
前言- IDEA如何配置?讓你敲代碼更輕松!
初識Java語言(一)- 基本資料型別及運算子
初識Java語言(二)- 方法以及遞回
初識Java語言(三)- 陣列
初識Java語言(四)-類和物件
文章目錄
- 一、包
- 包名
- 類的匯入與靜態匯入
- 在包中添加類
- 包訪問權限
- 二、繼承
- 類、超類與子類
- 重寫方法(override)
- this與super的區別:
- 子類構造器
- protected關鍵字
- 阻止繼承:final關鍵字
- 組合
一、包
包名
在講包名前,我們先來了解一下,包是用來干什么的?
Java中允許使用包(package),包將類組織在一個集合中,借助包可以方便管理組織自己的代碼,并將自己的代碼與別人的提供的代碼庫分開管理,
包是組織類的一種方式,使用包的主要目的就是保證類的唯一性,
在Windows作業系統中,我們都知道,同一個檔案夾下,不能同時出現兩個一樣的檔案名的檔案,而我們的java類,對應的就是一個.class檔案,所以產生了包,而包其實就可以理解為路徑中所存放的檔案夾,為了出現重命的類名,所以將各個類分布在不同的包(檔案夾)中,
而包名的命名:包名必須全部是小寫字母,且一般包的命名方式是所在公司的官網(域名)的逆序寫,假如www.xxxx.com,一般包名就是com.xxxx.——等等,
從編譯器的角度來看,嵌套的包之間沒有任何關系,例如:java.util包和java.util.jar包毫無關系,每一個包都是獨立的類集合,

類的匯入與靜態匯入
一個類可以使用所屬包中的所有類,以及其他包下的公共類(public class),
訪問另一個包的類有兩種方式:
-
使用完全限定名,也就是說在包名后面跟著類名,
java.util.Scanner scan = new java.util.Scanner(); //類名前面,直接跟包名 -
使用import關鍵字
import陳述句應該位于源檔案的頂部,且位于
package陳述句的后面,import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new scanner(); } }對于導包,我們還有一種比較簡單的方式,如下
import java.util.*;*,就是通配符,也就是在當前類中,可以直接使用util包的所有類,從而不需要再次導包了,值得注意的是,這里的匯入,并不是匯入util包下的所有類,這里跟C語言的include,不一樣,C語言中的include,是匯入頭檔案下的所有內容;而這里的import匯入,只會在需要使用這個包下的類的時候,才會匯入進來,
當然,對于import匯入包時,還需要特別注意一個問題,如下:
import java.util.*; import java.sql.*; public class Main { public static void main(String[] args) { Date date = new Date(); //error, java.util.Date 還是 java.sql.Date? } }此時進行編譯,就會產生一個如上面代碼的注釋部分的錯誤,此時的編譯器無法確定你想使用的是哪一個包下的Date類,現在就可以添加一個特定的import來解決這個問題,
import java.util.*; import java.sql.*; import java.util.Date; //特別指出是使用這個包下的Date類 public class Main { public static void main(String[] args) { Date date = new Date(); } }如果此時,兩個包中的Date都需要使用,那就只能使用完全限定名了,如下:
import java.util.*; import java.sql.*; public class Main { public static void main(String[] args) { java.util.Date date = new java.util.Date(); java.sql.Date date2 = new java.util.Date(); } }靜態匯入
我們還可以使用靜態匯入包的方式,進行代碼的縮寫,使用
import static可以匯入包中的靜態方法和靜態欄位,這樣就可以不必再加類名前綴,import static java.lang.System.*; public class Main { public static void main(String[] args) { out.println("hello world"); } }只是有這樣一種機制,可以進行代碼的縮寫,但在現實中,這樣的代碼,可能更不容易讀懂,所以大家使用時,酌情考慮,
在包中添加類
如果要想將類放入包中,就必須將包的名字放在源檔案的開頭,即就是放在定義這個包中各個類的代碼之前,如下:

如果沒有在這個源檔案的開頭,寫package陳述句,則這個源檔案中類就屬于無名包(unnamed package),無名包沒有包名,
基本規則:
- 在源檔案的最上方加一個package陳述句,可以指定該代碼在哪個包
- 包名盡量指定成唯一的名字,通常會使用公司的域名逆序形成
- 包名要和代碼路徑相匹配,例如:package com.xxxx.demo,那么所對應的檔案路徑就是com/xxxx/demo
- 如果一個源檔案沒有package陳述句,則該類會被放到無名包(默認包)中
IDEA建包程序:

包訪問權限
在之前的文章中,我們介紹過public和private,而private修飾的方法或成員變數,只能在當前這個類中訪問,
如果有個類,既沒有寫public,也沒有寫private訪問修飾限定符,則此時這個(類、方法或成員變數)可以在包內部(當前檔案夾下)的其他類中使用,但是不能在包外部(其他檔案夾下)的類中使用,如下代碼:
import com.xxxx.demo1;
//demo1 包
public class Main {
public static void main(String[] args) {
Test test = new Test(); //會報錯,訪問權限不夠,
}
}
//=====假設下面是第二個檔案夾下的檔案=====
import com.xxxx.demo2;
class Test { //訪問修飾限定符:沒寫,我們就稱為 默認
public int number;
}
public class Demo2 {
public int val;
}
訪問修飾限定符權限:
| 范圍 | private | 默認(default) | protected | public |
|---|---|---|---|---|
| 同包同類 | Y | Y | Y | Y |
| 同包不同類 | Y | Y | Y | |
| 不同包,子類 | Y | Y | ||
| 不同包,不同類 | Y |
其中,protected會在繼承中講到,我們繼續往下看!!!
二、繼承
繼承的基本思想就是:在已有類的基礎之上,創建新的類,繼承已存在的類得到就是復用了(繼承)這些類的方法,而且可以增加一些新的方法和成員變數,
類、超類與子類
我們先來舉個例子,比如一只貓和一只狗,它們了分別有自己的名字、性別、還是吃東西等等的一些性質,如下圖:

他們分別都有自己的這些特征,我們也可以很容易的發現,他們都有自己一些共有的特征:比如姓名,性別,所以如果我們分別在新建貓和狗的類,還得寫專屬于它們自己的成員變數,這樣的話,就顯得代碼重復累贅,如下圖這樣:
我們可以很清晰的看到,紅色框代碼部分,就是一模一樣的,所以出現了重復的代碼,而且這兩個類都是動物,所以說引出了一個繼承中的一個概念:“is -a”關系,
也就是說,什么是一個什么這樣的概念,就可能會用到繼承,
那該怎么實作繼承關系呢?我們來看下圖:

我們可以使用extends關鍵字來實作繼承關系,這樣的話,貓和狗兩個類,就能夠同時實作name和sex欄位,這就是繼承,
此時貓和狗類,我們稱為子類或者派生類,而Animal類我們稱為父類、基類或超類,
總結:
- 使用extends指定父類
- Java中一個子類只能繼承一個父類,(而C++中可以實作多繼承)
- 子類會繼承父類所有的public的欄位和方法
- 對于父類的private的欄位和方法,子類是無法進行訪問的
- 子類的實體中,也包含這父類的實體,可以使用
super關鍵字得到父類實體的參考,
重寫方法(override)

像上圖,子類和父類中,方法名和引數串列是一模一樣的,我們就稱為方法重寫(override),可能有人就會問,我該怎么呼叫相應的方法呢?
我們想呼叫Animal的eat方法,我們只需要new出一個Animal的物件,就能進行呼叫,當然,Cat類的實體物件也是如此,如果我們想在Cat類的實體物件呼叫父類的方法,則我們可以使用super關鍵字進行呼叫,如下圖:

切記:
-
super關鍵字,在使用的時候,只能呼叫他的直接父類的方法或欄位,比如:Animal類還繼承了一個類,此時Cat類中,使用super,則只會呼叫Animal中的方法或欄位,
-
在子類中重寫的方法,這個方法的訪問修飾限定符的等級,應高于或等于父類的方法的訪問修飾限定符,比如:父類中的eat方法是public修飾,而子類中的eat方法也應該是public,或者是更高的,(當然只是舉個例子,public就是最高的訪問修飾限定符了)
-
被重寫的方法,不能是被static修飾的
this與super的區別:

子類構造器
在上面說了,super關鍵字來呼叫父類的構造方法,那具體是如何進行呼叫的,我們來看一下具體的代碼實作:
public class Cat extends Animal{
public Cat(String name, String sex) {
super(name, sex); //呼叫父類的構造方法,super陳述句必須在子類構造器的第一行
System.out.println("Cat的構造方法");
}
public void eat() {
System.out.println("吃魚");
}
}
public class Animal {
public String name;
public String sex;
public Animal(String name, String sex) { //父類的構造方法
this.name = name;
this.sex = sex;
}
public void eat() {
System.out.println("吃肉");
}
}
總結:
- 使用super構造方法的陳述句必須放在子類構造方法中的第一行,
- 如果子類中,沒有顯示地呼叫父類的構造方法,將自動地呼叫超類的無參構造方法,
- 在進行子類的實體化時,會呼叫子類的構造方法,而在呼叫子類構造方法時,將會先呼叫父類的構造方法,也就是說:new Cat ,實際上將先會新建出父類,在父類新建完成后,才會回到子類的構造方法,進行新建子類,
下面是一道有趣的題:請問下列代碼的輸出結果是什么,
class X {
Y y=new Y();
public X() {
System.out.print("X");
}
}
class Y {
public Y() {
System.out.print("Y");
}
}
public class Z extends X {
Y y=new Y();
public Z() {
System.out.print("Z");
}
public static void main(String[] args) {
new Z();
}
}
上面的代碼的輸出結果是:YXYZ,
分析:
- 如果呼叫的是子類,那么在進入子類構造方法后,將先執行super陳述句(若沒寫,編譯器自帶),先構造父類,
- 在父類構造完成后,再次回到子類的構造方法,此時將先初始化當前類的成員變數,
- 在成員變數初始化之后,才會執行構造方法里面的陳述句,
上訴代碼執行流程圖:

protected關鍵字
在上文中,我寫了一個訪問修飾限定符的表,表中第3個protected關鍵字,
前面我們學了public和private訪問修飾限定符,public的權限有大了,對于public來說,整個工程都可以進行使用;而對于private來說,只能在當前的類中進行使用,二者之前,一個權限過大,一個權限過小,所以在Java的繼承中,還引入了這個關鍵字:protected;
對于protected來說,protected修飾的內容,在這個包下,可以直接使用,而在不同的包下,只有繼承了這個類,才能在不同的包下使用該類被protected修飾內容,
阻止繼承:final關鍵字
在前面的文章中,我們介紹過final關鍵字,final修飾的變數,在初始化之后,將不能被修改,
final int a = 10;
a = 20; //編譯出錯,此時的a被final修飾,存盤在方法區,且不能被修改
final也能修飾類,,表示不能再被繼承,稱為密封類,
final還能修飾方法,表示此時的方法不能被重寫,稱為密封方法,
切記:如果一個類被final修飾,那么其中的方法將自動地稱為final,但是不包括欄位,如果一個方法沒有被重寫并且還很短,編譯器將會對此進行優化處理,這個程序稱為行內,
組合
和繼承類似的,還有一個叫組合的概念,也是用于表達類之間的關系,也能夠達到代碼的重復使用,
例如:一個公司由很多人組合而成,有當經理的、職員的、保潔員的等等……
class Person {
public String name;
public String sex;
}
class Manager extends Person { //繼承 人
//經理的薪水
public double getSalary() {
}
}
class Staff extends Person { //繼承 人
//普通職員的薪水
public double getSalary() {
}
}
//組合
public class Company {
public Manager[] manager; //經理
public Staff[] staff; //普通職員
}
組合并沒有涉及到特殊的語法,僅僅只是將一個類的實體作為另一個類的欄位,這也是我們設計類的一種常用的方式或思想,
組合表示has- a 的語意:意為:一個事物 由 什么組合而成,也就是包含的意思,
繼承表示is-a的語意:意為:一個事物 是 一個什么事物的概念,
多多總結,相信大家能夠理解其中的意思!!!好啦,本期更新就到此結束啦,我們下期見!!!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/299519.html
標籤:java

