Java語(yǔ)言之包和繼承詳解
一、包
包名
在講包名前,我們先來(lái)了解一下,包是用來(lái)干什么的?
Java中允許使用包(package),包將類(lèi)組織在一個(gè)集合中。借助包可以方便管理組織自己的代碼,并將自己的代碼與別人的提供的代碼庫(kù)分開(kāi)管理。
包是組織類(lèi)的一種方式。使用包的主要目的就是保證類(lèi)的唯一性。
在Windows操作系統(tǒng)中,我們都知道,同一個(gè)文件夾下,不能同時(shí)出現(xiàn)兩個(gè)一樣的文件名的文件。而我們的java類(lèi),對(duì)應(yīng)的就是一個(gè).class
文件,所以產(chǎn)生了包,而包其實(shí)就可以理解為路徑中所存放的文件夾,為了出現(xiàn)重命的類(lèi)名,所以將各個(gè)類(lèi)分布在不同的包(文件夾)中。
而包名的命名:包名必須全部是小寫(xiě)字母,且一般包的命名方式是所在公司的官網(wǎng)(域名)的逆序?qū)懀偃鐆ww.xxxx.com,一般包名就是com.xxxx.——等等。
從編譯器的角度來(lái)看,嵌套的包之間沒(méi)有任何關(guān)系。例如:java.util包和java.util.jar包毫無(wú)關(guān)系。每一個(gè)包都是獨(dú)立的類(lèi)集合。
類(lèi)的導(dǎo)入與靜態(tài)導(dǎo)入
一個(gè)類(lèi)可以使用所屬包中的所有類(lèi),以及其他包下的公共類(lèi)(public class)。
訪問(wèn)另一個(gè)包的類(lèi)有兩種方式:
1.使用完全限定名,也就是說(shuō)在包名后面跟著類(lèi)名。
java.util.Scanner scan = new java.util.Scanner(); //類(lèi)名前面,直接跟包名
2.使用import關(guān)鍵字
import語(yǔ)句應(yīng)該位于源文件的頂部,且位于package語(yǔ)句的后面。
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new scanner(); } }
對(duì)于導(dǎo)包,我們還有一種比較簡(jiǎn)單的方式,如下
import java.util.*;
*,就是通配符。也就是在當(dāng)前類(lèi)中,可以直接使用util包的所有類(lèi),從而不需要再次導(dǎo)包了。值得注意的是,這里的導(dǎo)入,并不是導(dǎo)入util包下的所有類(lèi),這里跟C語(yǔ)言的include,不一樣。C語(yǔ)言中的include,是導(dǎo)入頭文件下的所有內(nèi)容;而這里的import導(dǎo)入,只會(huì)在需要使用這個(gè)包下的類(lèi)的時(shí)候,才會(huì)導(dǎo)入進(jìn)來(lái)。
當(dāng)然,對(duì)于import導(dǎo)入包時(shí),還需要特別注意一個(gè)問(wèn)題,如下:
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? } }
此時(shí)進(jìn)行編譯,就會(huì)產(chǎn)生一個(gè)如上面代碼的注釋部分的錯(cuò)誤。此時(shí)的編譯器無(wú)法確定你想使用的是哪一個(gè)包下的Date類(lèi)?,F(xiàn)在就可以添加一個(gè)特定的import來(lái)解決這個(gè)問(wèn)題。
import java.util.*; import java.sql.*; import java.util.Date; //特別指出是使用這個(gè)包下的Date類(lèi) public class Main { public static void main(String[] args) { Date date = new Date(); } }
如果此時(shí),兩個(gè)包中的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(); } }
靜態(tài)導(dǎo)入
我們還可以使用靜態(tài)導(dǎo)入包的方式,進(jìn)行代碼的縮寫(xiě)。使用import static
可以導(dǎo)入包中的靜態(tài)方法和靜態(tài)字段。這樣就可以不必再加類(lèi)名前綴。
import static java.lang.System.*; public class Main { public static void main(String[] args) { out.println("hello world"); } }
只是有這樣一種機(jī)制,可以進(jìn)行代碼的縮寫(xiě),但在現(xiàn)實(shí)中,這樣的代碼,可能更不容易讀懂。所以大家使用時(shí),酌情考慮。
在包中添加類(lèi)
如果要想將類(lèi)放入包中,就必須將包的名字放在源文件的開(kāi)頭,即就是放在定義這個(gè)包中各個(gè)類(lèi)的代碼之前。如下:
如果沒(méi)有在這個(gè)源文件的開(kāi)頭,寫(xiě)package語(yǔ)句,則這個(gè)源文件中類(lèi)就屬于無(wú)名包(unnamed package)。無(wú)名包沒(méi)有包名。
基本規(guī)則:
- 在源文件的最上方加一個(gè)package語(yǔ)句,可以指定該代碼在哪個(gè)包
- 包名盡量指定成唯一的名字,通常會(huì)使用公司的域名逆序形成
- 包名要和代碼路徑相匹配。例如:package com.xxxx.demo,那么所對(duì)應(yīng)的文件路徑就是com/xxxx/demo
- 如果一個(gè)源文件沒(méi)有package語(yǔ)句,則該類(lèi)會(huì)被放到無(wú)名包(默認(rèn)包)中
IDEA建包過(guò)程:
包訪問(wèn)權(quán)限
在之前的文章中,我們介紹過(guò)public
和private
。而private修飾的方法或成員變量,只能在當(dāng)前這個(gè)類(lèi)中訪問(wèn)。
如果有個(gè)類(lèi),既沒(méi)有寫(xiě)public,也沒(méi)有寫(xiě)private訪問(wèn)修飾限定符,則此時(shí)這個(gè)(類(lèi)、方法或成員變量)可以在包內(nèi)部(當(dāng)前文件夾下)的其他類(lèi)中使用,但是不能在包外部(其他文件夾下)的類(lèi)中使用。如下代碼:
import com.xxxx.demo1; //demo1 包 public class Main { public static void main(String[] args) { Test test = new Test(); //會(huì)報(bào)錯(cuò),訪問(wèn)權(quán)限不夠。 } } //=====假設(shè)下面是第二個(gè)文件夾下的文件===== import com.xxxx.demo2; class Test { //訪問(wèn)修飾限定符:沒(méi)寫(xiě),我們就稱(chēng)為 默認(rèn) public int number; } public class Demo2 { public int val; }
訪問(wèn)修飾限定符權(quán)限:
范圍 | private | 默認(rèn)(default) | protected | public |
---|---|---|---|---|
同包同類(lèi) | Y | Y | Y | Y |
同包不同類(lèi) | Y | Y | Y | |
不同包,子類(lèi) | Y | Y | ||
不同包,不同類(lèi) | Y |
其中,protected會(huì)在繼承中講到,我們繼續(xù)往下看?。?!
二、繼承
繼承的基本思想就是:在已有類(lèi)的基礎(chǔ)之上,創(chuàng)建新的類(lèi)。繼承已存在的類(lèi)得到就是復(fù)用了(繼承)這些類(lèi)的方法,而且可以增加一些新的方法和成員變量。
類(lèi)、超類(lèi)與子類(lèi)
我們先來(lái)舉個(gè)例子,比如一只貓和一只狗。它們了分別有自己的名字、性別、還是吃東西等等的一些性質(zhì)。如下圖:
他們分別都有自己的這些特征,我們也可以很容易的發(fā)現(xiàn),他們都有自己一些共有的特征:比如姓名,性別。所以如果我們分別在新建貓和狗的類(lèi),還得寫(xiě)專(zhuān)屬于它們自己的成員變量,這樣的話,就顯得代碼重復(fù)累贅,如下圖這樣:
我們可以很清晰的看到,紅色框代碼部分,就是一模一樣的,所以出現(xiàn)了重復(fù)的代碼。而且這兩個(gè)類(lèi)都是動(dòng)物,所以說(shuō)引出了一個(gè)繼承中的一個(gè)概念:“is -a”關(guān)系。
也就是說(shuō),什么是一個(gè)什么這樣的概念。就可能會(huì)用到繼承。
那該怎么實(shí)現(xiàn)繼承關(guān)系呢?我們來(lái)看下圖:
我們可以使用extends
關(guān)鍵字來(lái)實(shí)現(xiàn)繼承關(guān)系,這樣的話,貓和狗兩個(gè)類(lèi),就能夠同時(shí)實(shí)現(xiàn)name和sex字段。這就是繼承。
此時(shí)貓和狗類(lèi),我們稱(chēng)為子類(lèi)
或者派生類(lèi)
。而Animal類(lèi)我們稱(chēng)為父類(lèi)
、基類(lèi)
或超類(lèi)
。
總結(jié):
- 使用extends指定父類(lèi)
- Java中一個(gè)子類(lèi)只能繼承一個(gè)父類(lèi)。(而C++中可以實(shí)現(xiàn)多繼承)
- 子類(lèi)會(huì)繼承父類(lèi)所有的public的字段和方法
- 對(duì)于父類(lèi)的private的字段和方法,子類(lèi)是無(wú)法進(jìn)行訪問(wèn)的
- 子類(lèi)的實(shí)例中,也包含這父類(lèi)的實(shí)例??梢允褂胹uper關(guān)鍵字得到父類(lèi)實(shí)例的引用。
重寫(xiě)方法(override)
像上圖,子類(lèi)和父類(lèi)中,方法名和參數(shù)列表是一模一樣的。我們就稱(chēng)為方法重寫(xiě)(override)??赡苡腥司蜁?huì)問(wèn),我該怎么調(diào)用相應(yīng)的方法呢?
我們想調(diào)用Animal的eat方法,我們只需要new出一個(gè)Animal的對(duì)象,就能進(jìn)行調(diào)用,當(dāng)然,Cat類(lèi)的實(shí)例對(duì)象也是如此。如果我們想在Cat類(lèi)的實(shí)例對(duì)象調(diào)用父類(lèi)的方法,則我們可以使用super關(guān)鍵字進(jìn)行調(diào)用。如下圖:
切記:
- super關(guān)鍵字,在使用的時(shí)候,只能調(diào)用他的直接父類(lèi)的方法或字段。比如:Animal類(lèi)還繼承了一個(gè)類(lèi),此時(shí)Cat類(lèi)中,使用super,則只會(huì)調(diào)用Animal中的方法或字段。
- 在子類(lèi)中重寫(xiě)的方法,這個(gè)方法的訪問(wèn)修飾限定符的等級(jí),應(yīng)高于或等于父類(lèi)的方法的訪問(wèn)修飾限定符。比如:父類(lèi)中的eat方法是public修飾,而子類(lèi)中的eat方法也應(yīng)該是public,或者是更高的。(當(dāng)然只是舉個(gè)例子,public就是最高的訪問(wèn)修飾限定符了)
- 被重寫(xiě)的方法,不能是被static修飾的
this與super的區(qū)別:
子類(lèi)構(gòu)造器
在上面說(shuō)了,super關(guān)鍵字來(lái)調(diào)用父類(lèi)的構(gòu)造方法,那具體是如何進(jìn)行調(diào)用的,我們來(lái)看一下具體的代碼實(shí)現(xiàn):
public class Cat extends Animal{ public Cat(String name, String sex) { super(name, sex); //調(diào)用父類(lèi)的構(gòu)造方法,super語(yǔ)句必須在子類(lèi)構(gòu)造器的第一行 System.out.println("Cat的構(gòu)造方法"); } public void eat() { System.out.println("吃魚(yú)"); } }
public class Animal { public String name; public String sex; public Animal(String name, String sex) { //父類(lèi)的構(gòu)造方法 this.name = name; this.sex = sex; } public void eat() { System.out.println("吃肉"); } }
總結(jié):
- 使用super構(gòu)造方法的語(yǔ)句必須放在子類(lèi)構(gòu)造方法中的第一行。
- 如果子類(lèi)中,沒(méi)有顯示地調(diào)用父類(lèi)的構(gòu)造方法,將自動(dòng)地調(diào)用超類(lèi)的無(wú)參構(gòu)造方法。
- 在進(jìn)行子類(lèi)的實(shí)例化時(shí),會(huì)調(diào)用子類(lèi)的構(gòu)造方法,而在調(diào)用子類(lèi)構(gòu)造方法時(shí),將會(huì)先調(diào)用父類(lèi)的構(gòu)造方法。也就是說(shuō):new Cat ,實(shí)際上將先會(huì)新建出父類(lèi),在父類(lèi)新建完成后,才會(huì)回到子類(lèi)的構(gòu)造方法,進(jìn)行新建子類(lèi)。
下面是一道有趣的題:請(qǐng)問(wèn)下列代碼的輸出結(jié)果是什么。
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(); } }
上面的代碼的輸出結(jié)果是:YXYZ。
分析:
- 如果調(diào)用的是子類(lèi),那么在進(jìn)入子類(lèi)構(gòu)造方法后,將先執(zhí)行super語(yǔ)句(若沒(méi)寫(xiě),編譯器自帶),先構(gòu)造父類(lèi)。
- 在父類(lèi)構(gòu)造完成后,再次回到子類(lèi)的構(gòu)造方法。此時(shí)將先初始化當(dāng)前類(lèi)的成員變量。
- 在成員變量初始化之后,才會(huì)執(zhí)行構(gòu)造方法里面的語(yǔ)句。
上訴代碼執(zhí)行流程圖:
protected關(guān)鍵字
在上文中,我寫(xiě)了一個(gè)訪問(wèn)修飾限定符的表,表中第3個(gè)protected關(guān)鍵字。
前面我們學(xué)了public和private訪問(wèn)修飾限定符,public的權(quán)限有大了,對(duì)于public來(lái)說(shuō),整個(gè)工程都可以進(jìn)行使用;而對(duì)于private來(lái)說(shuō),只能在當(dāng)前的類(lèi)中進(jìn)行使用。二者之前,一個(gè)權(quán)限過(guò)大,一個(gè)權(quán)限過(guò)小。所以在Java的繼承中,還引入了這個(gè)關(guān)鍵字:protected;
對(duì)于protected來(lái)說(shuō),protected修飾的內(nèi)容,在這個(gè)包下,可以直接使用。而在不同的包下,只有繼承了這個(gè)類(lèi),才能在不同的包下使用該類(lèi)被protected修飾內(nèi)容。
阻止繼承:final關(guān)鍵字
在前面的文章中,我們介紹過(guò)final關(guān)鍵字,final修飾的變量,在初始化之后,將不能被修改。
final int a = 10; a = 20; //編譯出錯(cuò),此時(shí)的a被final修飾,存儲(chǔ)在方法區(qū),且不能被修改
final也能修飾類(lèi),,表示不能再被繼承,稱(chēng)為密封類(lèi)。
final還能修飾方法,表示此時(shí)的方法不能被重寫(xiě),稱(chēng)為密封方法。
切記:如果一個(gè)類(lèi)被final修飾,那么其中的方法將自動(dòng)地稱(chēng)為final,但是不包括字段。如果一個(gè)方法沒(méi)有被重寫(xiě)并且還很短,編譯器將會(huì)對(duì)此進(jìn)行優(yōu)化處理,這個(gè)過(guò)程稱(chēng)為內(nèi)聯(lián)。
組合
和繼承類(lèi)似的,還有一個(gè)叫組合的概念,也是用于表達(dá)類(lèi)之間的關(guān)系,也能夠達(dá)到代碼的重復(fù)使用。
例如:一個(gè)公司由很多人組合而成,有當(dāng)經(jīng)理的、職員的、保潔員的等等……
class Person { public String name; public String sex; } class Manager extends Person { //繼承 人 //經(jīng)理的薪水 public double getSalary() { } } class Staff extends Person { //繼承 人 //普通職員的薪水 public double getSalary() { } } //組合 public class Company { public Manager[] manager; //經(jīng)理 public Staff[] staff; //普通職員 }
組合并沒(méi)有涉及到特殊的語(yǔ)法,僅僅只是將一個(gè)類(lèi)的實(shí)例作為另一個(gè)類(lèi)的字段,這也是我們?cè)O(shè)計(jì)類(lèi)的一種常用的方式或思想。
組合表示has- a 的語(yǔ)義:意為:一個(gè)事物 由 什么組合而成,也就是包含的意思。
繼承表示is-a的語(yǔ)義:意為:一個(gè)事物 是 一個(gè)什么事物的概念。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Java分頁(yè)簡(jiǎn)介_(kāi)動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了Java分頁(yè)簡(jiǎn)介的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08一文讓你搞懂如何手寫(xiě)一個(gè)redis分布式鎖
既然要搞懂Redis分布式鎖,那肯定要有一個(gè)需要它的場(chǎng)景。高并發(fā)售票問(wèn)題就是一個(gè)經(jīng)典案例。本文就來(lái)利用這個(gè)場(chǎng)景手寫(xiě)一個(gè)redis分布式鎖,讓你徹底搞懂它2022-11-11Java8新特性之再見(jiàn)Permgen_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
這篇文章主要介紹了Java8新特性之再見(jiàn)Permgen的相關(guān)知識(shí),非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下吧2017-06-06sqlserver和java將resultSet中的記錄轉(zhuǎn)換為學(xué)生對(duì)象
這篇文章主要介紹了如何利用sqlserver和java將resultSet中的記錄轉(zhuǎn)換為學(xué)生對(duì)象,附有超詳細(xì)的代碼,需要的朋友可以參考一下,希望對(duì)你有所幫助2021-12-12解決SSLContext.getInstance()中參數(shù)設(shè)置TLS版本無(wú)效的問(wèn)題
這篇文章主要介紹了解決SSLContext.getInstance()中參數(shù)設(shè)置TLS版本無(wú)效的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-01-01spring?boot?導(dǎo)出數(shù)據(jù)到excel的操作步驟(demo)
這篇文章主要介紹了spring?boot?導(dǎo)出數(shù)據(jù)到excel的實(shí)現(xiàn)步驟,文中通過(guò)打開(kāi)一個(gè)平時(shí)練習(xí)使用的springboot的demo給大家詳細(xì)介紹,需要的朋友可以參考下2022-03-03mybatis?一對(duì)多映射?column屬性的注意事項(xiàng)說(shuō)明
這篇文章主要介紹了mybatis?一對(duì)多映射?column屬性的注意事項(xiàng)說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。2022-01-01Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(13)
下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你2021-07-07將List集合中的map對(duì)象轉(zhuǎn)為L(zhǎng)ist<對(duì)象>形式實(shí)例代碼
這篇文章主要介紹了將List集合中的map對(duì)象轉(zhuǎn)為L(zhǎng)ist<對(duì)象>形式實(shí)例代碼,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01關(guān)于SpringBoot整合Canal數(shù)據(jù)同步的問(wèn)題
大家都知道canal是阿里巴巴旗下的一款開(kāi)源工具,純java開(kāi)發(fā),支持mysql數(shù)據(jù)庫(kù),本文給大家介紹SpringBoot整合Canal數(shù)據(jù)同步的問(wèn)題,需要的朋友可以參考下2022-03-03