有些人寫了一陣子 Java,可是對於 Java 的 package 跟 import 還是不
太了解很多人以為原始碼 .java 檔案中的 import 會讓編譯器把所 import
的程式通通寫到編譯好的 .class 檔案中,或是認為 import 跟 C/C++ 的
#include 相似,實際上,這是錯誤的觀念。
讓我們先了解一下,Java 的 package 到底有何用處。
其實,package 名稱就像是我們的姓,而 class 名稱就像是我們的名字
。package 名稱有很多 . 的,就好像是複姓。比如說 java.lang.String,就
是複姓 java.lang,名字為 String 的類别;java.io.InputStream 則是複姓
java.io,名字為 InputStream 的類别。
Java 會使用 package 這種機制的原因也非常明顯,就像我們取姓名一樣
,光是一間學校的同一屆同學中,就有可能會出現不少同名的同學,如果不取
姓的話,那學校在處理學生資料,或是同學彼此之間的稱呼,就會發生很大的
困擾。相同的,全世界的 Java 類别數量,恐怕比台灣人口還多,而且還不斷
的在成長當中,如果類别不使用套件名稱,那在用到相同名稱的不同類别時,
就會產生極大的困擾。幸運的是,Java 的套件名稱我們可以自己取,不像人
的姓沒有太大的選擇 ( 是以有很多同名同姓的 ),如果依照 Sun 的規範來取
套件名稱,那理論上不同人所取的套件名稱不會相同 ( 請參閱 "命名慣例"
的相關文章 ),也就不會發生名稱衝突的情況。
可是問題來了,因為很多套件的名稱非常的長,在寫程式時,會多打好多
字,花費不少時間,比如說:
java.io.InputStream is = java.lang.System.in;
java.io.InputStreamReader isr= new java.io.InputStreamReader(is);
java.io.BufferedReader br = new java.io.BufferedReader(isr);
實在是不美觀又麻煩。於是,Sun 想了一個辦法,就是 import。
這個 import 就是在程式一開頭的時候,先說明程式中會用到那些類别的簡稱,也就是隻稱呼名字,不稱呼他的姓。首先,在檔案開頭寫:
import java.lang.System;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
這幾行說明了這四個姓名的類别,在程式中隻用他的名字來稱呼,是以當程式
中提到 System 就是指 java.lang.System,而 InputStream 就是指
java.io.InputStream,依此類推。於是原來的程式就變成:
InputStream = System.in;
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
這樣看起來是不是清爽多了呢?如果這些類别用的次數很多,那就更能體會到
import 的好處了。可是這樣還是不夠,因為懶是人的天性,還是會有人覺得
打太多 import 了也很浪費時間,於是 Sun 又提供了一個方法:
import java.lang.*;
import java.io.*;
意思就是,等一下程式中提到的沒有姓名的類别,不是姓 java.lang,就是姓
java.io,如果這兩個裡面有同樣名字的類别,而不幸的你又隻用名字稱呼這
個類别,那編譯器仍然會跟你抱怨,因為它還是不知道你說的這個類别指那一
個姓的類别。那可不可以再懶一點呢,隻寫:
import java.*;
歷史告訴我們,人可以懶,但不能太懶,這樣是不行的。因為那些類别是姓
java.io 而不是姓 java。就像姓『諸葛』的人應該不會喜歡你稱他為『諸』
先生吧。
為甚麼我一開始說 import 跟 #include 不同呢?因為 import 的功能
到此為止,它不像 #include 一樣,會将檔案内容載入進來。import 隻是請
編譯器幫你打字,讓編譯器把沒有姓的類别加上姓,并不會把别的檔案的程
式碼寫進來。如果你想練習打字,可以不要使用 import,隻要在用到類别的
時候,用它的全部姓名來稱呼它就行了(就像例子一開始那樣),跟使用
import 完全沒有甚麼兩樣。
另外,雖然人不可以太懶,但是 Sun 還是幫我們多偷了一點懶。因為
java.lang 這個套件實在是太常太常太常用到了,幾乎沒有程式不用它的,
是以不管你有沒有寫 import java.lang;,編譯器都會自動幫你補上,也就
是說編譯器隻要看到沒有姓的類别,它就會自動去 java.lang 裡面找找看,
看這個類别是不是屬於這個套件的。是以我們就不用特别去
import java.lang 了。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
import導入聲明可分為兩中:
1>單類型導入(single-type-import)
例:import java.util.ArrayList;
2>按需類型導入(type-import-on-demand)
例:import java.util.*;
以這樣兩種方式導入包中的任何一個public的類和接口(隻有public類和接口才能被導入)
*導入聲明僅導入類型而不導入子包;這就是為什麼稱它們為單類型導入和按需類型導入聲明的原因.
*導入的類或接口的簡名(simple name)具有編譯單元作用域.這表示該類型簡名可以在導入語句所在的編譯單元的任何地方使用.這并不意味着你可以使用該類型所有成員的簡名,而隻能使用類型自身的簡名.
例如: java.lang包中的public類都是自動導入的,包括Math和System類.但是,你不能使用簡名PI()和gc(),而必須使用Math.PI()和System.gc().你不需要鍵入的是java.lang.Math.PI()和java.lang.System.gc().
程式員有時會導入目前包或java.lang包,這是不需要的,因為目前包的成員本身就在作用域内,而java.lang包是自動導入的.java編譯器會忽略這些備援導入聲明(redundant import declarations).即使像這樣
import java.util.ArrayList;
import java.util.*;
多次導入,也可編譯通過.編譯器會将備援導入聲明忽略.
使用按需導入聲明是否會降低Java代碼的執行效率?絕對不會!
Java編譯器産生的類檔案僅包含編譯單元實際使用到的類或接口的符号引用.
這是否意味着你總是可以使用按需導入聲明?是,也不是!
在類似Demo的非正式開發中使用按需導入聲明顯得很有用.
然而,有這四個理由讓你可以放棄這種聲明:
1>編譯速度:在一個很大的項目中,它們會極大的影響編譯速度.但在小型項目中使用在編譯時間上可以忽略不計.
2>命名沖突:解決避免命名沖突問題的答案就是使用全名.而按需導入恰恰就是使用導入聲明初衷的否定.
3>說明問題:全名的使用是自說性的.畢竟進階語言的代碼是給人看的.
4>無名包問題:如果在編譯單元的頂部沒有包聲明,Java編譯器首選會從無名包中搜尋一個類型,然後才是按需類型聲明.如果有命名沖突就會産生問題.
Sun的工程師一般不使用按需類型導入聲明.這你可以在他們的代碼中找到:
在java.util.Properties類中的導入聲明:
import java.io.IOException;
import java.io.printStream;
import java.io.printWrite;
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.util.Hashtable;
你可以看到有趣的是,她連java.util.Hashtable也導入,這可是在目前包中啊!
參考資料:http://xgtian.blog.51cto.com/3844449/737269
作 者:Angel_Kitty
出 處:https://www.cnblogs.com/ECJTUACM-873284962/
關于作者:阿裡雲ACE,目前主要研究方向是Web安全漏洞以及反序列化。如有問題或建議,請多多賜教!
版權聲明:本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連結。
特此聲明:所有評論和私信都會在第一時間回複。也歡迎園子的大大們指正錯誤,共同進步。或者直接私信我
聲援部落客:如果您覺得文章對您有幫助,可以點選文章右下角【推薦】一下。您的鼓勵是作者堅持原創和持續寫作的最大動力!
歡迎大家關注我的微信公衆号IT老實人(IThonest),如果您覺得文章對您有很大的幫助,您可以考慮賞部落客一杯咖啡以資鼓勵,您的肯定将是我最大的動力。thx.
我的公衆号是IT老實人(IThonest),一個有故事的公衆号,歡迎大家來這裡讨論,共同進步,不斷學習才能不斷進步。掃下面的二維碼或者收藏下面的二維碼關注吧(長按下面的二維碼圖檔、并選擇識别圖中的二維碼),個人QQ和微信的二維碼也已給出,掃描下面👇的二維碼一起來讨論吧!!!
歡迎大家關注我的Github,一些文章的備份和平常做的一些項目會存放在這裡。