⑴ 如何查看一個jar文件是用什麼版本jdk編譯的
有一種稍微麻煩的辦法,可以試試
在jar包中,用winrar解壓一個類文件,然後在命令行下面輸入
javap -verbose classname
會輸出一些信息,大致如下:
Compiled from "HtmlCrawer.java"
public class org.eagleeye.html.HtmlCrawer extends java.lang.Object
SourceFile: "HtmlCrawer.java"
minor version: 0
major version: 50
Constant pool:
const #1 = class #2; // org/eagleeye/html/HtmlCrawer
const #2 = Asciz org/eagleeye/html/HtmlCrawer;
const #3 = class #4; // java/lang/Object
const #4 = Asciz java/lang/Object;
const #5 = Asciz client;
....
後面省略了,可以看到前面有兩行:
minor version: 0
major version: 50
表示了類文件的版本,具體內容可以參考:
2008-05-08 17:27 class version一:要解決的問題
我們在嘗鮮 JDK1.5 的時候,相信不少人遇到過 Unsupported major.minor version 49.0 錯誤,當時定會茫然不知所措。因為剛開始那會兒,網上與此相關的中文資料還不多,現在好了,網上一找就知道是如何解決,大多會告訴你要使用 JDK 1.4 重新編譯。那麼至於為什麼,那個 major.minor 究竟為何物呢?這就是本篇來講的內容,以使未錯而先知。
我覺得我是比較幸運的,因為在遇到那個錯誤之前已研讀過《深入 Java 虛擬機》第二版,英文原書名為《Inside the Java Virtual Machine》( Second Edition),看時已知曉 major.minor 藏匿於何處,但沒有切身體會,待到與 Unsupported major.minor version 49.0 真正會面試,正好是給我驗證了一個事實。
首先我們要對 Unsupported major.minor version 49.0 建立的直接感覺是:JDK1.5 編譯出來的類不能在 JVM 1.4 下運行,必須編譯成 JVM 1.4 下能運行的類。(當然,也許你用的還是 JVM 1.3 或 JVM 1.2,那麼就要編譯成目標 JVM 能認可的類)。這也解決問題的方向。
二:major.minor 棲身於何處
何謂 major.minor,且又居身於何處呢?先感性認識並找到 major.minor 來。
寫一個 Java Hello World! 代碼,然後用 JDK 1.5 的編譯器編譯成,HelloWorld.java
public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } } public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } }
用 JDK 1.5 的 javac HelloWorld.java 編譯出來的位元組碼 HelloWorld.class 用 UltraEdit 打開來的內容如圖所示:
從上圖中我們看出來了什麼是 major.minor version 了,它相當於一個軟體的主次版本號,只是在這里是標識的一個 Java Class 的主版本號和次版本號,同時我們看到 minor_version 為 0x0000,major_version 為 0x0031,轉換為十制數分別為0 和 49,即 major.minor 就是 49.0 了。
三:何謂 major.minor 以及何用
Class 文件的第 5-8 位元組為 minor_version 和 major_version。Java class 文件格式可能會加入新特性。class 文件格式一旦發生變化,版本號也會隨之變化。對於 JVM 來說,版本號確定了特定的 class 文件格式,通常只有給定主版本號和一系列次版本號後,JVM 才能夠讀取 class 文件。如果 class 文件的版本號超出了 JVM 所能處理的有效范圍,JVM 將不會處理該 class 文件。
在 Sun 的 JDK 1.0.2 發布版中,JVM 實現支持從 45.0 到 45.3 的 class 文件格式。在所有 JDK 1.1 發布版中的 JVM 都能夠支持版本從 45.0 到 45.65535 的 class 文件格式。在 Sun 的 1.2 版本的 SDK 中,JVM 能夠支持從版本 45.0 到46.0 的 class 文件格式。
1.0 或 1.2 版本的編譯器能夠產生版本號為 45.3 的 class 文件。在 Sun 的 1.2 版本 SDK 中,Javac 編譯器默認產生版本號為 45.3 的 class 文件。但如果在 javac 命令行中指定了 -target 1.2 標志,1.2 版本的編譯器將產生版本號為 46.0 的 class 文件。1.0 或 1.1 版本的 JVM 上不能運行使用-target 1.2 標志所產生的 class 文件。
JVM 實現的 第二版中修改了對 class 文件主版本號和次版本號的解釋。對於第二版而言,class 文件的主版本號與 Java 平台主發布版的版本號保持一致(例如:在 Java 2 平台發布版上,主版本號從 45 升至 46),次版本號與特定主平台發布版的各個發布版相關。因此,盡管不同的 class 文件格式可以由不同的版本號表示,但版本號不一樣並不代表 class 文件格式不同。版本號不同的原因可能只是因為 class 文件由不同發布版本的 java 平台產生,可能 class 文件的格式並沒有改變。
上面三段節選自《深入 Java 虛擬機》,啰嗦一堆,JDK 1.2 開啟了 Java 2 的時代,但那個年代仍然離我們很遠,我們當中很多少直接跳在 JDK 1.4 上的,我也差不多,只是項目要求不得不在一段時間里委屈在 JDK 1.3 上。不過大致我們可以得到的信息就是每個版本的 JDK 編譯器編譯出的 class 文件中都帶有一個版本號,不同的 JVM 能接受一個范圍 class 版本號,超出范圍則要出錯。不過一般都是能向後兼容的,知道 Sun 在做 Solaris 的一句口號嗎?保持對先前版本的 100% 二進制兼容性,這也是對客戶的投資保護。
四:編譯器比較及症節之所在
現在不妨從 JDK 1.1 到 JDK 1.7 編譯器編譯出的 class 的默認 minor.major version 吧。(又走到 Sun 的網站上翻騰出我從來都沒用過的古董來)
JDK 編譯器版本 target 參數 十六進制 minor.major 十進制 minor.major jdk1.1.8 不能帶 target 參數 00 03 00 2D 45.3 jdk1.2.2 不帶(默認為 -target 1.1) 00 03 00 2D 45.3 jdk1.2.2 -target 1.2 00 00 00 2E 46.0 jdk1.3.1_19 不帶(默認為 -target 1.1) 00 03 00 2D 45.3 jdk1.3.1_19 -target 1.3 00 00 00 2F 47.0 j2sdk1.4.2_10 不帶(默認為 -target 1.2) 00 00 00 2E 46.0 j2sdk1.4.2_10 -target 1.4 00 00 00 30 48.0 jdk1.5.0_11 不帶(默認為 -target 1.5) 00 00 00 31 49.0 jdk1.5.0_11 -target 1.4 -source 1.4 00 00 00 30 48.0 jdk1.6.0_01 不帶(默認為 -target 1.6) 00 00 00 32 50.0 jdk1.6.0_01 -target 1.5 00 00 00 31 49.0 jdk1.6.0_01 -target 1.4 -source 1.4 00 00 00 30 48.0 jdk1.7.0 不帶(默認為 -target 1.6) 00 00 00 32 50.0 jdk1.7.0 -target 1.7 00 00 00 33 51.0 jdk1.7.0 -target 1.4 -source 1.4 00 00 00 30 48.0 Apache Harmony 5.0M3 不帶(默認為 -target 1.2) 00 00 00 2E 46.0 Apache Harmony 5.0M3 -target 1.4 00 00 00 30 48.0
上面比較是 Windows 平台下的 JDK 編譯器的情況,我們可以此作些總結:
1) -target 1.1 時 有次版本號,target 為 1.2 及以後都只用主版本號了,次版本號為 0
2) 從 1.1 到 1.4 語言差異比較小,所以 1.2 到 1.4 默認的 target 都不是自身相對應版本
3) 1.5 語法變動很大,所以直接默認 target 就是 1.5。也因為如此用 1.5 的 JDK 要生成目標為 1.4 的代碼,光有 -target 1.4 不夠,必須同時帶上 -source 1.4,指定源碼的兼容性,1.6/1.7 JDk 生成目標為 1.4 的代碼也如此。
4) 1.6 編譯器顯得較為激進,默認參數就為 -target 1.6。因為 1.6 和 1.5 的語法無差異,所以用 -target 1.5 時無需跟著 -source 1.5。
5) 注意 1.7 編譯的默認 target 為 1.6
6) 其他第三方的 JDK 生成的 Class 文件格式版本號同對應 Sun 版本 JDK
7) 最後一點最重要的,某個版本的 JVM 能接受 class 文件的最大主版本號不能超過對應 JDK 帶相應 target 參數編譯出來的 class 文件的版本號。
上面那句話有點長,一口氣讀過去不是很好理解,舉個例子:1.4 的 JVM 能接受最大的 class 文件的主版本號不能超過用 1.4 JDK 帶參數 -target 1.4 時編譯出的 class 文件的主版本號,也就是 48。
因為 1.5 JDK 編譯時默認 target 為 1.5,出來的位元組碼 major.minor version 是 49.0,所以 1.4 的 JVM 是無法接受的,只有拋出錯誤。
那麼又為什麼從 1.1 到 1.2、從 1.2 到 1.3 或者從 1.3 到 1.4 的 JDK 升級不會發生 Unsupported major.minor version 的錯誤呢,那是因為 1.2/1.3/1.4 都保持了很好的二進制兼容性,看看 1.2/1.3/1.4 的默認 target 分別為 1.1/1.1/1.2 就知道了,也就是默認情況下1.4 JDK 編譯出的 class 文件在 JVM 1.2 下都能載入執行,何況於 JVM 1.3 呢?(當然要去除使用了新版本擴充的 API 的因素)
五:找到問題解決的方法
那麼現在如果碰到這種問題該知道如何解決了吧,還會像我所見到有些兄弟那樣,去找個 1.4 的 JDK 下載安裝,然後用其重新編譯所有的代碼嗎?其實大可不必如此費神,我們一定還記得 javac 還有個 -target 參數,對啦,可以繼續使用 1.5 JDK,編譯時帶上參數 -target 1.4 -source 1.4 就 OK 啦,不過你一定要對哪些 API 是 1.5 JDK 加入進來的了如指掌,不能你的 class 文件拿到 JVM 1.4 下就會 method not found。目標 JVM 是 1.3 的話,編譯選項就用 -target 1.3 -source 1.3 了。
相應的如果使用 ant ,它的 javac 任務也可對應的選擇 target 和 source
<javac target="1.4" source="1.4" ............................/>
如果是在開發中,可以肯定的是現在真正算得上是 JAVA IDE 對於工程也都有編譯選項設置目標代碼的。例如 Eclipse 的項目屬性中的 Java Compiler 設置,如圖
自已設定編譯選項,你會看到選擇不同的 compiler compliance level 是,Generated class files compatibility 和 Source compatibility 也在變,你也可以手動調整那兩項,手動設置後你就不用很在乎用的什麼版本的編譯器了,只要求他生成我們希望的位元組碼就行了,再引申一下就是即使源代碼是用 VB 寫的,只要能編譯成 JVM 能執行的位元組碼都不打緊。在其他的 IDE 也能找到相應的設置對話框的。
其他時候,你一定要知道當前的 JVM 是什麼版本,能接受的位元組碼主版本號是多少(可對照前面那個表)。獲息當前 JVM 版本有兩種途徑:
第一:如果你是直接用 java 命令在控制台執行程序,可以用 java -version 查看當前的 JVM 版本,然後確定能接受的 class 文件版本
第二:如果是在容器中執行,而不能明確知道會使用哪個 JVM,那麼可以在容器中執行的程序中加入代碼System.getProperty("java.runtime.version"); 或 System.getProperty("java.class.version"),獲得 JVM 版本和能接受的 class 的版本號。
最後一絕招,如果你不想針對低版本的 JVM 用 target 參數重新編譯所有代碼;如果你仍然想繼續在代碼中用新的 API 的話;更有甚者,你還用了 JDK 1.5 的新特性,譬如泛型、自動拆裝箱、枚舉等的話,那你用 -target 1.4 -source 1.4 就沒法編譯通過,不得不重新整理代碼。那麼告訴你最後一招,不需要再從源代碼著手,直接轉換你所正常編譯出的位元組碼,繼續享用那些新的特性,新的 API,那就是:請參考之前的一篇日誌:Retrotranslator讓你用JDK1.5的特性寫出的代碼能在JVM1.4中運行,我就是這么用的,做好測試就不會有問題的。
六:再議一個實際發生的相關問題
這是一個因為拷貝 Tomcat 而產生的 Unsupported major.minor version 49.0 錯誤。情景是:我本地安裝的是 JDK 1.5,然後在網上找了一個 EXE 的 Tomcat 安裝文件安裝了並且可用。後來同事要一個 Tomcat,不想下載或安裝,於是根據我以往的經驗是把我的 Tomcat 整個目錄拷給他應該就行了,結果是拿到他那裡瀏覽 jsp 文件都出現 Unsupported major.minor version 49.0 錯誤,可以確定的是他安裝的是 1.4 的 JDK,但我還是有些納悶,先前對這個問題還頗有信心的我傻眼了。慣性思維是編譯好的 class 文件拿到低版本的 JVM 會出現如是異常,可現並沒有用已 JDK 1.5 編譯好的類要執行啊。
後來仔細看異常信息,終於發現了 %TOMCAT_HOME%\common\lib\tools.jar 這一眉目,因為 jsp 文件需要依賴它來編譯,打來這個 tools.jar 中的一個 class 文件來看看,49.0,很快我就明白原來這個文件是在我的機器上安裝 Tomcat 時由 Tomcat 安裝程序從 %JDK1.5%\lib 目錄拷到 Tomcat 的 lib 目錄去的,造成在同事機器上編譯 JSP 時是 1.4 的 JVM 配搭著 49.0 的 tools.jar,那能不出錯,於是找來 1.4 JDK 的 tools.jar 替換了 Tomcat 的就 OK 啦。
⑵ Java11的新功能有哪些
Java 11 JDK中已計劃的新功能
目前來看,JDK 11已有九個已經確認的新功能,而且還有更多新功能仍在考慮之中。計劃的新功能包括:
HTTP客戶端(標准),這個功能於JDK 9中引入並在JDK 10中得到了更新,現在終於轉正了。該API通過CompleteableFutures提供非阻塞請求和響應語義,可以聯合使用以觸發相應的動作。自從JDK 9和10中引入該功能後,JDK 11完全重寫了該功能,現在其實現完全是非同步的。RX Flow的概念也得到了實現,這樣就無需為了支持HTTP/2而創造許多概念了。現在,在用戶層請求發布者和響應發布者與底層套接字之間追蹤數據流更容易了。這降低了復雜性,並最大程度上提高了HTTP/1和HTTP/2之間的重用的可能性。Epsilon垃圾回收器,被稱為「no-op」回收器,它僅負責內存分配,卻沒有實現任何實際的內存回收機制。Epsilon回收器可以用於性能測試、內存壓力測試和虛擬機介面。它還可以用於短生命周期的任務。lambda參數的局部變數語法,可以消除隱含類型表達式中正式參數定義的語法與局部變數定義語法的不一致。這樣就能在隱含類型的lambda表達式中定義正式參數時使用var了。Java的類文件格式將被擴展,以支持新的常量池,CONSTANT_Dynamic。其目標是降低開發新形式的可實現類文件約束帶來的成本和干擾。採用Curve25519和Curve448加密的密鑰交換比現有的Diffie-Hellman橢圓曲線密鑰交換方式更有效、更安全。根據IETF的資料,Curve25519和Curve448兩種橢圓曲線採用常量時間的實現方式,以及不會發生異常的數乘實現,能更好地抵抗各種旁路攻擊,包括時序攻擊、緩存攻擊等。該提案的目標是為密鑰交換方法提供一個API和實現,同時開發一個平台無關、純Java的的實現。由於該提案採用了復雜且精密的模算數,因此還是有風險的。飛行記錄儀(Flight Recorder)將提供低開銷的數據收集框架,用來調試Java應用程序和HotSpot JVM。飛行記錄儀是Oracle的商業版JDK的功能,但在JDK 11中,其代碼將移動到公開代碼庫中,這樣所有人都能使用該功能了。Iclouded將作為API,以事件的形式產生或消耗數據,同時提供緩存機制、二進制數據工具,同時支持配置和事件過濾。該提案還提議為OS、HotSpot和JDK庫提供事件。更新platform API以支持Unicode版本10.0,從而使Java跟上潮流。預計以下的類將支持:lang包中的Character和Stringawt.font包中的NumericShapertext包中的Bidi、BreakIterator和Normalizer實現ChaCha20和Poly1305加密演算法。ChaCha20是種相對較新的流加密演算法,能代替舊的、不安全的R4流加密。ChaCha20將與Poly1305認證演算法配對使用。ChaCha20和ChaCha20-Poly1305加密實現將通過crypto.CipherSpi API於SunJCE(Java加密擴展)中提供。增強Java啟動器,使之能夠運行單一文件的Java源代碼,使得應用程序可以直接從源代碼運行。單文件程序常見於小型工具,或開發者初學Java時使用。而且,單一源代碼文件有可能會編譯成多個類文件,這會增加打包開銷。由於這些原因,在運行程序之前進行編譯,已成為了不必要的步驟。Java JDK 11仍在開發中的新功能
Java 11的創建者們還在考慮幾個對JDK 11的變更或新功能的提案:
給Java添加raw字元串字面值。這樣可以更容易地以人類可閱讀的形式書寫字元序列,而無需特殊的Java標記。這樣也能更容易地將非Java語法的字元串提供給Java使用,還能支持多行字元串,而無需使用特殊的標記。擴展switch語句,使之能作為語句或表達式使用。這樣還能改進switch處理null值的方式。這些改動可以簡化編程,同時為switch支持模式匹配做准備。嵌套的訪問控制,對應於Java當前的嵌套類型。嵌套可以讓邏輯上屬於同一代碼實體但被編譯到不同的類文件中的類互相訪問對方的私有成員,而無需讓編譯器插入擴大訪問許可權的方法。JDK 11刪除的功能
Java EE和CORBA模塊從Java SE9就成了不推薦使用(deprecated),並計劃在未來的版本中刪除。這個未來版本就是JDK 11。
Java SE 6於2006年12越發布,它為Java EE平台提供了整套的Web服務技術棧:JAX-WS(Java API for XML-based Web Services),JAXB(Java Architecture for XML Binding),JAF(JavaBeans Activation Framework),以及Common Annotations for Java。這些年來,Java EE版本在不斷進化,這給Java SE造成了許多麻煩,例如加入與Java SE無關的技術,以及同時維護兩個Java版本的困難變得更大。由於獨立的Java EE版本由第三方網站提供,Oracle說Java SE或JDK中已經沒有必要提供Java EE了。
當然,一些依賴於JDK中的Java EE API及工具的應用程序將無法編譯或運行。將JDK 6、7或8移植到新版本時將會產生二進制不兼容和源代碼不兼容。Oracle說,受到這些影響的開發者可以部署相應的Java EE版本。
CORBA來自於二十世紀九十年代,Oracle說,現在用CORBA開發現代Java應用程序已經沒有意義了,維護CORBA的成本已經超過了保留它帶來的好處。
但是刪除CORBA將使得那些依賴於JDK提供部分CORBA API的CORBA實現無法運行。目前還沒有第三方CORBA版本,也不確定是否會有第三方願意接手CORBA API的維護工作。
JavaFX已經被移除,因此已經與Java JDK每年兩次的更新無關。
⑶ 我的電腦安裝jdk11版本顯示不兼容,但是我們老師要求我們使用最新版的,怎麼辦
你這是因為運行環境的JDK和編譯環境的JDK版本不同造成的,在低運行版本的環境下運行高編譯版本的內容一般就會報這個問題。
⑷ JAVA的JDK最新版本是多少的
目前測試版本為jdk12,穩定版本為jdk11,但是用的最多還是jdk8
⑸ java的JDK更新到什麼版本了
Standard Edition(標准版)的最新版:jdk 14。
Early-Access(先行版)的最新版:jdk15。
LTS(長期支持版)的最新版:jdk 11.0.6。
JRE(Java Runtime Environment,Java運行時環境),包含了java虛擬機、java基礎類庫。是使用java語言編寫的程序運行所需要的軟體環境。
它相當於操作系統部分,提供了Java程序運行時所需要的基本條件和許多Java基礎類,例如,IO類、GUI控制項類、網路類等。JRE是提供給普通用戶使用的,如果你只想運行別人開發好的Java程序,那麼,你的計算機上必須且只需安裝JRE。
JDK(Java Development Kit,Java開發工具包),它包含編譯工具、解釋工具、文檔製作工具、打包工具多種與開發相關的工具,是提供給Java開發人員使用的。JDK包含了JRE,同時還包含了編譯java源碼的編譯器javac,還包含了很多java程序調試和分析的工具:jconsole,jvisualvm等工具軟體,還包含了java程序編寫所需的文檔和demo例子程序。
⑹ 為何我的jdk版本是jdk 11卻用不了var語法,IDEA中使用var推斷類型報錯
哈哈,Java里用的不是var語法啊,var語法一般是出現在JS等語言里的
Java中定義對象:
類名 對象名 = 值;
例如:Integer num = new Integer(100);
Javascript(ECMAScript)中定義對象:
var 對象名 = 值;
例如:var arr = new Array(100);
⑺ class編譯默認用jdk11
方法如下:
1、在系統變數中,添加【JAVA_HOME】,路徑選擇jdk安裝路徑。
2、在用戶變數中,配置PATH。
變數值填寫JDK的安裝目錄下的bin目錄,因「JAVA_HOME」已配置好,所以可通過JAVA_HOME變數來設置,這樣比較靈活,下次要變更JDK的話,只需修改JAVA_HOME即可 。
3、配置CLASS_PATH。
變數值填寫JDK相關的jar包,也是通過JAVA_HOME變數來設置,可直接寫%JAVA_HOME%libdt.jar;%JAVA_HOME%lib ools.jar,然後連續【確定】