程序包不存在?无源文件?找不到文件?找不到或无法加载主类?
1.首先在電腦桌面上創建一個test文件夾,然后使用記事本寫兩個單純的Java類里邊,分別是HelloWorld.java和BeInvoking.java,目標是HelloWorld調用BeInvoking.java里邊的方法。
首先在test的上一級目錄也就是桌面上嘗試進行編譯。
首先把cmd調到test的上一層目錄上,也就是桌面路徑,嘗試進行編譯。
找不到文件,因為桌面上沒有這兩個文件,可以理解。
然后i進入test目錄,再嘗試編譯執行。
執行成功,因為HelloWorld.java調用了BeInvoking.java里邊的方法,所以不用編譯BeInvoking.java,編譯器會當前文件夾下尋找BeInvoking.java自動編譯。
編譯完成后,test目錄下多了編譯后的兩個字節碼文件。
2.要是編譯后的字節碼文件放到其他地方會怎么樣呢?
在test下創建一個target文件夾,打算把.class文件放到這個文件夾下。先把前面生成的.class文件刪了。
編譯語法如下,-d是指定編譯后的存放目錄,這里我指定的目錄為./tatget,.是當前位置的意思,./targetd就代表當前位置下的target文件夾。
編譯成功,并且target文件夾下多了兩個字節碼文件。
在test目錄下執行看看。
執行失敗,找不到字節碼文件。可以理解。那么轉換到target文件夾下應該能成功吧。試試看。
還真可以。
那我不在target文件夾然后使用絕對路徑呢?(太亂了清個屏)
好吧,不知道怎么描述一個文件夾下的文件。使用 “ 文件夾路徑/文件名” 或者
“文件夾路徑.文件名” 好像都不行。
3.接下來引入包機制,把BeInvoking.java放入包cn.com中。也就是在第一行加入package cn.com; 先把整個target目錄刪了。
在test位置嘗試進行編譯。
加了個package cn.com就不行了?根據報錯也就是說HelloWorld可以編譯,但是BeInvoking.java找不到了。
那可能是它倆在不在同一個包內包導致的,在HelloWorld.java里邊導入BeInvoking看看行不行。也就是在HelloWorld.java第一行加入import cn.com.BeInvoking;
試著編譯看看。
好家伙,直接程序包不存在。
是不是不能同時編譯呢?那我分開編譯,先把BeInvoking先編譯了,然后是HelloWorld.
先編譯BeInvoking,test文件夾下生成了BeInvoking.class.
然后我再編譯HelloWorld看能不能成功。
還是不行啊。菜鳥教程里說包路徑和文件路徑要一致,那我的BeInvoking.class不應該在test文件夾下,而是應該在cn.com這樣的目錄結構下。先把上一步產生的test文件夾下的BeInvoking.class給刪了。指定目錄重新編譯BeInvoking.java看看。
在當前目錄也就是test下編譯BeInvoking.java。test文件夾下產生了一個新的文件夾。查看目錄結構是cn->com,里邊有BeInvoking.class??戳诉@本編譯命令挺強大的,直接幫我生成包名對應的目錄了。
那我再編譯HelloWorld看看。
哇塞,居然成功了!
執行看看。
也是可以執行了。
先來個小總結:如果調用的類在跟自己相同的包下,不用提前編譯那個被調用的類,編譯器會自動找到那個類進行編譯。如果不在同一個包內,編譯器就找不到了,所以得提前進行被調用的類的編譯,然后再編譯調用其他類的主類。
不對,那我要是提前把BeInvoking.java放到./cn/com文件夾下呢,編譯器是不是就可以根據HelloWorld.java中import的包路徑找到它了?試試看!
在這之前先把這前cn/com下上一次編譯成功產生的BeInvoking.class文件刪了,同時把test文件夾下的BeInvoking.java復制一份到cn/com文件夾下,并且回來把test文件夾下的BeInvoking.java給刪掉。也就是把test文件夾下的BeInvoking.java剪切到cn/com下。
上一次編譯成功后test文件夾下也產生了HelloWorld.class,也一并刪掉,以免影響實驗。
實驗前的環境如下:
好的,現在先不編譯BeInvoking.java,直接編譯HelloWorld.java。
nice!居然成功了!
然后在./cn/com下發現了BeInvoking.class文件。
不出意外,執行也應該可以成功。
果然如此!
上一次的總結不太行?,F在修正一下:
編譯一個類A時,如果A導入了類B,那么編譯器首先根據導入的包路徑去當前路徑下的包路徑尋找B類的源代碼,找到后進行編譯,找不到則A的編譯失敗!
這個當前路徑下好像比較抽象的樣子。試著分析一波:
首先,編譯器這個軟件安裝在我的JDK安裝目錄里邊,也就是D:\LZZ-SoftwereDownload\Java 16.0.1\bin下。
然后我打開cmd,cmd這個軟件應該安裝在操作系統的目錄里邊,也就是c盤下的某個位置。
接著我打開cmd,cmd每一次打開都會指向一個目錄,且可以通過cd命令轉換目錄。也就是我認為的當前路徑下。
那么cmd這個指向的這個目錄是干啥用的呢?cmd可以調用其他程序,是不是它在調用其他程序的時候把這個目錄給被調用程序這個目錄參數呢?
查了一下javac命令還可以使用-classpath命令指定類路徑。那么它會把-classpath所指定的路徑當成“當前路徑”嗎?試一試就知道了!
首先,先刪除之前生成的test目錄下的HelloWorld.class文件和test/cn/com下的BeInvoking.class.
初始環境如下:
然后,cmd里邊退出test目錄,就在桌面吧??傊且粋€不存在HelloWorld.java的文件夾就好。
然后,編譯HelloWorld.java,但得傳遞classpath變量。classpath所指定的目錄為HelloWorld.java所在的目錄。執行結果如下
好家伙,直接找不到文件?離譜了。
網上查了一下,-classpath好像是給虛擬機讀的 ,編譯器編譯的話不用-classpath選項,直接寫全路徑就好了,試一試。
這回HelloWorld是可以找到了,但是BeInvoking又找不到了,提示是cn.com不存在,cn.com在test目錄下是存在的,那么提示不存在的話就是說在cmd的”當前目錄“也就是桌面上找不到cn.com了。
所以還得跟編譯器說明運行的起始目錄,也就是test目錄,作為真的當前目錄?難道得使用-classpath?因為BeInvoking.java是在以test目錄為起始目錄,然后往下依次尋找cn/com才能找到的。所以得把這個起始目錄告訴編譯器編譯器才能找到BeInvoking.java。試一試加上-classpath,把test目錄給他弄過去。
居然成了!我tm真是個小天才!修改之前的推測,-classpath并不是只給虛擬機讀的。
那為什么HelloWorld得用全路徑呢?這設定真奇怪。
運行一下試試看。cmd的指向目錄還是在桌面。
這?連HelloWorld都找不到?查了一下HelloWorld.class是已經在test目錄下生成了啊。不科學啊。
分析一下,我在cmd中調用了java命令,然后操作系統在環境變量中存下的地址中找到了java的虛擬機這個程序的地址,然后啟動了java的虛擬機,然后cmd給了虛擬機C:\Users\LZZ\Desktop\test\HelloWorld這個地址讓虛擬機去執行。我編譯HelloWorld.java的時候就是這么干的,按道理說是可以的啊?難道虛擬機還得有個起始目錄,然后在起始目錄下去尋找C:\Users\LZZ\Desktop\test\HelloWorld這個文件?那么虛擬機的起始目錄就是cmd給他的桌面目錄(因為cmd是指向桌面目錄的)?如果按照這個想法,那么我就得使用-classpath命令改變這個cmd給虛擬機的起始目錄,然后既然有了起始目錄HelloWorld.class就不需要全路徑了?試一試!
果真如此啊!!!!!!!
總結一下:
編譯一個類時如果當前源代碼文件不在當前cmd指向的文件夾中,得用全路徑,如果改類引用了另外一個類,而且被引用的這個類不在同一個包,也就是不在同一個文件夾下,那么得使用-classpath指明被引用的這個類的起始目錄位置!然后從這個起始目錄位置根據包名尋找指定目錄下的源代碼文件。
但是執行時不一樣,如果字節碼文件不在cmd所指向的文件夾中,不能使用全路徑去執行這個字節碼文件,得使用-classpath指明這個字節碼文件的所在目錄的起始位置,這里我稱之為工作目錄,為什么說是起始位置呢,因為這個類如果有包結構的話肯定得按包結構對應的目錄尋找下去。
那么如果A類引用了B類中的方法和C類中的方法,而且他們的包結構都不一樣,比方說A類在C盤,B類在D盤,C類在E盤,那該怎么辦呢,如果B類還調用C類的方法呢?根據之前的分析。目測應該是把所有的路徑寫上。
試一試。
實驗環境為:
首先在C盤的C:\tmp目錄下創建類A,類A放在a1.a2.a3.包里邊,同時導入類B和類C,調用類B和類C的方法。
接著在D盤中的D:\CloudMusic下創建B類,B類放b1.b2.b3包中,B類導入C類,調用C類的方法。
最后在E盤根目錄中創建C類,C類放c1.c2.c3包中。
具體如下:
緊接著進行編譯,我現在想只編譯A類,讓編譯器同時把B類和C類全都編譯了,因為A類會調用C類和B類。
分析一波:
首先得把編譯后的.class文件放到一個指定的目錄下吧,所以得用-d選線指定一個目錄,就放在桌面上的一個target文件中好了。然后根據以上的經驗,還得告訴編譯器B類和C類的起始地址,那它們的起始地址是啥呢,就是B.java和C.java所存在的目錄嗎?感覺不行啊!試試看:
好家伙,無源文件,可是我的源文件C:\tmp\A.java已經寫上去了啊,看來是格式有問題,讀不到C:\tmp\A.java這一部分就截止了。或者說不能指定兩個起始目錄嗎,那這樣的話可真沒意思了。
先把C類的起始目錄去掉,只留一個起始目錄:
好,并不是無源文件了,那說明讀到源文件A.java了。但是編譯源文件還是報錯。那說明不能指定兩個起始目錄?這設計絕對不科學,一定是我的語法有問題。
檢查了一下,發現我的兩個起始目錄把B.java和C.java給帶上了,它應該是一個目錄才對吧。改一下!
還是不行,難道真的不能指定兩個起始目錄嗎?
上邊我用的分號;隔開兩個起始地址,那說不定不是分號;呢,改成正斜杠/:
試一試:
nice!居然不是無源文件了,省去了我靠度娘的功夫!前進了一小步。
不能編譯成功在意料之中,因為編譯完A類之后編譯器會去指定的起始目錄去找B類和C類,然后在起始目錄下根據包名對應的包目錄,找B.java和C.java,而B.java和C.java直接再起始目錄下,并沒有存在對應的包目錄,所以找不到包目錄,報了不存在包的提示。
所以,我這個設計是有缺陷的,在我定義了類A的時候,寫了package a1.a2.a3,說明類A對應的包是a1.a2.a3,那么我應該創建三個文件夾a1,a2,a3,其中a2放在a1中,a3放在a2中,且A.java放在a3中,文件目錄結構要和包結構對上,才是正常的!
先改成三個絕對地址試試看:
無效文件名可還行。
看來我的斜杠/失敗了!
上個度娘,還是網友們強大,好像是空格 隔開就行了。
參考鏈接:javac編譯多個java文件以及-cp、-classpath、-sourcepath
試試:
好家伙,亂碼!好像我記事本保存源代碼的格式默認是UTF-8的,而編譯器是按GBK來讀的。
把源代碼的保存格式全換成ANSI的了,ANSI在中文windows系統上指的就是GBK。
再試試看:
完事大吉,晚上吃雞!
查看我的桌面,也就是-d所指的class文件保存的地址,發現桌面上果然自動生成了一個target文件,并且文件產生了對應的目錄結構!生成了對應的.class文件!
看看能不能執行,執行的時候不能是絕對路徑,得是起始地址+包地址的形式,那么我的起始地址應該是桌面上的target文件夾,包地址我在之前的例子上是直接寫HelloWorld,因為HelloWorld.class直接在起始地址中,那現在我的包地址應該得帶上包名吧:
直接寫A果然不行,虛擬機找不到A.class文件。
寫上包名:
萬事大吉!
之前的想法是只編譯A類,讓編譯器自動編譯B類和C類,但是以上編譯的時候我直接把A類、B類、C類的絕對路徑寫上了,這太不美觀了,純度不夠,要是有100個類,那不得全都寫出來,累死了都!所以目標是只編譯A類,剩下的交給編譯器來找!
上邊也分析過了,原因應該是寫類的時候沒有把包名和目錄結構對應上,現在改一下看看能不能成功!
改一下目錄結構:
好,現在包名跟目錄結構對上了!
寫上B類和C類的起始位置,然后是A類的絕對路徑:
很好,一點面子不給,為什么找不到b1.b2.b3啊,你tm去D:\CloudMusic底下找啊,我直接裂開。
難道是我的斜杠/語法是錯的?把C類的起始位置給去掉試試看:
并沒有報b1.b2.b3不存在,那說明b1.b2.b3找到了。那說明就是我的/語法不對了。
查了一下萬能的度娘,好像只有一個辦法,就是先把所有的源代碼的絕對路徑放到一個txt文件夾下,然后使用@語法。
雖說很麻煩,但是試試看吧!
首先先把桌面上的target文件夾清空,那個等下看里邊有沒有.cass文件就知道是否執行成功了。
然后在桌面創建一個txt,就叫MyJava.txt吧:
最后執行一下試試看:
還真的可以。
但是好像也不是很方便的樣子。
差不多就這樣吧,加上雜七雜八的事搞了我一天,佛了。
總結
以上是生活随笔為你收集整理的程序包不存在?无源文件?找不到文件?找不到或无法加载主类?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cpu与外设工作原理
- 下一篇: 关于JAVA调用dll的学习总结