91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java 16 有什么新特征

發布時間:2021-06-17 18:05:56 來源:億速云 閱讀:196 作者:chen 欄目:編程語言

這篇文章主要講解了“ Java 16 有什么新特征”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“ Java 16 有什么新特征”吧!

Java 16新特性

Java 16 有什么新特征

2021年3月16日,甲骨文正式發布了Java  16!想當年JDK1.6新出的場景和歷歷在目,一瞬間,版本已經變成了16,真正體會了一把什么叫做光陰似箭,滄海桑田。雖然目前大部分的場合,Java8還占著主導地位,但我猜想各位Javaer應該對Java16的新特性也大有興趣吧!

看完之后我覺得這次更新還是很有意思的,我就精選幾個Java16的新特性,供大家一飽眼福!(大家可以自己建個項目用起來試試)

支持模式匹配的instanceof

想想你是怎么用instanceof的吧,一個例子:

if (obj instanceof String) {     String s = (String) obj;    // grr...     ... }

這代碼是不是讓人蛋疼,我都知道是個String了,還讓我強轉一下,該改進一下啦~

if (obj instanceof String s) {     //這里s隨你用了 從類型判斷,到變量定義,類型轉換,一氣呵成,爽不爽? }

進一步的,還可以這么用,模式變量s在判斷條件里直接使用

if (obj instanceof String s && s.length() > 5) {     flag = s.contains("jdk"); }

不過要小心,下面的用法是錯誤的(原因就不多解釋啦):

if (obj instanceof String s || s.length() > 5) {    // Error!     ... }

Records類型

我們對Java最大的意見是啥?當然是太繁瑣了,一個簡單的功能,繁重的語法要整出好幾十行,不急,改進這就來了,看看新的Recodes類型吧!

假設你現在有這么一個類:

Java 16 有什么新特征

這是一個典型的不可變的數據對象,equals ()方法,  hashCode()方法,toString()方法其實都是比較通用的。但是我們不得不為它多寫那么幾行代碼。雖然有IDE的鼎力協助,但是看上去還是不怎么爽(如果沒有IDE,更要哭了)。不過沒事Records來了!用Records來表示上面的類,你只需要:

record Point(int x, int y) { }

是不是特別簡單,感覺心里特別爽?record類和普通的class不太一樣,它會幫你隱式生成一些字段和構造函數。比如上面的record就會編譯成這樣:

record Point(int x, int y) {     // 隱式生成字段     private final int x;     private final int y;     // 隱式生成構造函數,并帶上所有的參數     Point(int x, int y) {         this.x = x;         this.y = y;     } }

ZGC并發線程處理

ZGC是The Z Garbage Collector,是JDK  11中推出的一款低延遲垃圾回收器,它嘗試解決GC之痛,也就是停頓。

同時,它也將面向以TB為單位的超大規模的內存。在Java  16中,ZGC的線程棧處理的眾多操作,從檢查點移動到了并發階段,這樣意味著停頓更小了。(后面準備出個zgc相關的文章,順便測一波這次的停頓優化時長)

彈性元空間

在Java虛擬機中,元空間用來保存一些類的元信息,并且,元空間中的數據是可以被垃圾回收的。但不幸的是,空閑的未被使用的元空間并不會歸還給操作系統,這就導致了內存浪費。

這個新特性就是為了解決這個問題,它使得虛擬機可以從元空間中歸還未使用的內存,從而更加有效得利用物理內存。同時有一個新的虛擬機參數可以用來控制這種回收的執行強度:-XX:MetaspaceReclaimPolicy=(balanced|aggressive|none)

Unix Domain套接字

Unix  Domain套接字本身提供給了一套兼容于網絡編程,但是更加可靠、高效、安全的進程間通信方式,它不需要經過網絡協議棧,不需要打包拆包、計算校驗和、維護序號和應答等,只是將應用層數據從一個進程拷貝到另一個進程。

在Java 16中,已經可以直接使用這種套接字(Unix-domain (AF_UNIX),雖然叫做UNIX套接字,windows 10和Windows  Server 2019也是可以使用的)了。為了支持Unix  Domain套接字,新增了專門的java.net.UnixDomainSocketAddress類,下面看一下它的使用:

 Java 16 有什么新特征

新的打包工具

提供了一個新的打包工具jpackage,用來打包獨立的Java應用程序。這個工具可以生成windows上的exe和msi,MacOS上的pkg和dmg,以及linux上的deb和rpm。它很好的給用戶提供了一鍵式安裝Java程序的好方法。

比如,對于非模塊化的應用,可以這么打包:

jpackage --name myapp --input lib --main-jar main.jar 或者 直接指定main class jpackage --name myapp --input lib --main-jar main.jar --main-class myapp.Main

對于模塊化的應用:

jpackage --name myapp --module-path lib -m myapp 或者直接指定main class jpackage --name myapp --module-path lib -m myapp/myapp.Main

值對象錯誤使用的警告

值對象,比如java.lang.Integer,  java.lang.Double之類的不變對象,在廢棄構造函數的基礎上,進一步標記為forRemoval(不要再使用它們的構造函數了哦!)。

同時,如果在值對象上進行同步,將會被警告,比如:

Double d = 20.0; synchronized (d) { ... } // javac和hotsopt都會警告 Object o = d; synchronized (o) { ... } // HotSpot 會警告

在虛擬機層面,還提供了參數可以在虛擬機層面控制報錯行為:

  • -XX:DiagnoseSyncOnValueBasedClasses=1 將這種同步行為視為致命錯誤

  • -XX:DiagnoseSyncOnValueBasedClasses=2 打開日志,在控制臺和飛行記錄儀中記錄這種同步行為

默認限制使用JDK內部API

對于一些JDK內部的API,作出了更嚴格的限制。比如 com.sun.*, jdk.*, and  org.*這些包里的API,從Java  16開始,默認已經禁止使用了。因此,鼓勵大家使用標準API,而不是內部API(點擊這里查看可以替換的內部API)。比如說下面這句代碼,在Java  16中將報錯:

System.out.println(sun.security.util.SecurityConstants.ALL_PERMISSION);

錯誤示例:

Exception in thread "main" java.lang.IllegalAccessError: class Test   (in unnamed module @0x5e481248) cannot access class   sun.security.util.SecurityConstants (in module java.base) because   module java.base does not export sun.security.util to unnamed   module @0x5e481248

同時,JDK還提供--illegal-access參數用來控制對內部API的使用:

  • --illegal-access=permit 允許使用內部API

  • --illegal-access=warn 允許使用內部API,不過每次使用會得到一個警告

  • --illegal-access=debug  允許使用內部API,會更詳細的打印每一個錯誤的調用堆棧,用它你就可以找到你在哪里有不正確的調用,就可以修復那些不合適的使用

  • --illegal-access=deny 禁止使用內部API

孵化項目:向量API

我們知道,像Go這樣的后起之秀,已經在內部使用了AVX指令,性能飆升。Java在這方面也不甘示弱,在Java  16中,向量API作為一個孵化項目,允許我們直接使用SIMD指令來提高性能(如果有效使用,這波就帶你起飛了)。

讓我們先一睹為快吧!

下面是一個簡單的標量計算:

void scalarComputation(float[] a, float[] b, float[] c) {    for (int i = 0; i < a.length; i++) {         c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;    } }

重點來了,使用AVX2帶你起飛:

//256位的向量浮點運算 static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;  void vectorComputation(float[] a, float[] b, float[] c) {     int i = 0;     int upperBound = SPECIES.loopBound(a.length);     for (; i < upperBound; i += SPECIES.length()) {         // FloatVector va, vb, vc;         var va = FloatVector.fromArray(SPECIES, a, i);         var vb = FloatVector.fromArray(SPECIES, b, i);         var vc = va.mul(va).                     add(vb.mul(vb)).                     neg();         vc.intoArray(c, i);     }      for (; i < a.length; i++) {         c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;     } }

孵化項目:外部鏈接API

你是不是有抱怨過JNI太難用了?沒關系,JNI的進化版來了,這就是外部鏈接器!它提供了一個靜態的,純Java的訪問本地native  代碼的方法,它將極大簡化我們調用本地代碼的過程。

新的API:

  • LibraryLookup::ofDefault:返回被JVM加載的庫,可以看到所有這些庫的符號

  • LibraryLookup::ofPath:加載指定路徑

  • LibraryLookup::ofLibrary :根據庫名,加載庫

下面代碼展示了,使用Java調用clang庫中的clang_getClangVersion()方法:

LibraryLookup libclang = LibraryLookup.ofLibrary("clang"); LibraryLookup.Symbol clangVersion = libclang.lookup("clang_getClangVersion");

另外一個重要的類是C鏈接器:

interface CLinker {     MethodHandle downcallHandle(LibraryLookup.Symbol func,                                 MethodType type,                                 FunctionDescriptor function);     MemorySegment upcallStub(MethodHandle target,                              FunctionDescriptor function); }

downcallHandle()表示在Java中調用本地方法;upcallStub()方法在native方法中調用java代碼。

下面的代碼展示了如何在Java代碼中,調用C函數size_t strlen(const char *s):

MethodHandle strlen = CLinker.getInstance().downcallHandle(         LibraryLookup.ofDefault().lookup("strlen"),         MethodType.methodType(long.class, MemoryAddress.class),         FunctionDescriptor.of(C_LONG, C_POINTER)     );

上面代碼首先找到strlen符號;然后描述它的簽名。最后使用downcallHandle()得到表示strlen()函數的MethodHandle對象;最后,就可以調用strlen()方法啦~

try (MemorySegment str = CLinker.toCString("Hello")) {    long len = strlen.invokeExact(str.address()); // 5 }

反過來,也可以把Java函數作為參數傳遞給C函數進行回調:

比如有一個C函數:

void qsort(void *base, size_t nmemb, size_t size,            int (*compar)(const void *, const void *));

要調用這個C函數,必須準備一個函數指針compar,為了使用它,我們首先要得到它的MethodHandle:

MethodHandle qsort = CLinker.getInstance().downcallHandle(         LibraryLookup.ofDefault().lookup("qsort"),         MethodType.methodType(void.class, MemoryAddress.class, long.class,                               long.class, MemoryAddress.class),         FunctionDescriptor.ofVoid(C_POINTER, C_LONG, C_LONG, C_POINTER)     );

接著,用一個純Java類來實現compar函數:

class Qsort {     static int qsortCompare(MemoryAddress addr1, MemoryAddress addr2) {             return MemoryAccess.getIntAtOffset(MemorySegment.ofNativeRestricted(),                                                 addr1.toRawLongValue()) -                     MemoryAccess.getIntAtOffset(MemorySegment.ofNativeRestricted(),                                                addr2.toRawLongValue());     } }

然后需要一個MethodHandle指向上述函數:

MethodHandle comparHandle     = MethodHandles.lookup()                    .findStatic(Qsort.class, "qsortCompare",                                MethodType.methodType(int.class,                                                      MemoryAddress.class,                                                      MemoryAddress.class));

然后,使用upcallStub()方法,得到一個函數指針(應該說是用Java描述的C函數指針):

MemorySegment comparFunc     = CLinker.getInstance().upcallStub(comparHandle,                                             FunctionDescriptor.of(C_INT,                                                                   C_POINTER,                                                                   C_POINTER)); );

最后,把這個"C函數指針"傳給C函數:

try (MemorySegment array = MemorySegment.allocateNative(4 * 10)) {     array.copyFrom(MemorySegment.ofArray(new int[] { 0, 9, 3, 4, 6, 5, 1, 8, 2, 7 }));     qsort.invokeExact(array.address(), 10L, 4L, comparFunc.address());     int[] sorted = array.toIntArray(); // [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ] }

好了,這就是使用外部鏈接API來使用本地代碼的全過程,是不是很酷炫呢?

預覽功能:密封類

類的繼承是面向對象的一個重要特性,但是濫用繼承對對象模型的建模也是非常不利的。對于這一點,Java還有較大的改進空間,密封類,正式對對象繼承的一種重大改進。

首先,來看JDK內部的一個例子:

package java.lang;  abstract class AbstractStringBuilder { ... } public final class StringBuffer  extends AbstractStringBuilder { ... } public final class StringBuilder extends AbstractStringBuilder { ... }

AbstractStringBuilder有兩個子類StringBuffer和StringBuilder。但是,我們的代碼卻無法繼承AbstractStringBuilder,因為AbstractStringBuilder是包內可見的,并不是public的。在很多場合,我們的對象模式其實并不希望徹底公開,我們有時候僅僅希望只有一些指定的類可以繼承,而不是可以任由繼承擴展。這就是密封類的設計初衷。

密封類/接口在聲明的時候,就可以指定哪些類可以從這里繼承,比如:

package com.example.geometry;  public abstract sealed class Shape     permits Circle, Rectangle, Square { ... }

注意新關鍵字sealed,它表示被修飾的類或者接口是密封的,緊接著使用permits關鍵字,指定哪些子類可以繼承它,這里只有Circle,Rectangle和Square可以從Shape繼承(繼承類和密封類必須要在同一個模塊,如果在unamed模塊,就需要在同一個package)。

使用密封類,還有一些限制,比如:

1.子類必須是直接繼承,而不是間接的

2.子類必須說明如果處理得到的密封屬性,三選一,必選一個:

  • 子類標記為final,一了百了

  • 子類也作為sealed類,并做有限的繼承擴展

  • 子類申明為non-sealed,公開使用(這種情況,密封類的初衷就被打破了,繼承關系就不可控了)

下面的代碼說明了這3種情況:

package com.example.geometry; //使用final public final class Circle extends Shape { ... } //使用sealed public sealed class Rectangle extends Shape      permits TransparentRectangle, FilledRectangle { ... } public final class TransparentRectangle extends Rectangle { ... } public final class FilledRectangle extends Rectangle { ... } //使用non-sealed public non-sealed class Square extends Shape { ... }

感謝各位的閱讀,以上就是“ Java 16 有什么新特征”的內容了,經過本文的學習后,相信大家對 Java 16 有什么新特征這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

抚顺县| 衡东县| 北碚区| 广宗县| 开化县| 宜兴市| 庆阳市| 始兴县| 化德县| 呈贡县| 涟水县| 甘孜县| 涿鹿县| 松滋市| 得荣县| 隆德县| 五常市| 东山县| 邹城市| 格尔木市| 天气| 汽车| 若羌县| 广宗县| 武功县| 麦盖提县| 丹棱县| 当涂县| 新河县| 德格县| 新野县| 夏河县| 嘉黎县| 濉溪县| 全州县| 平乡县| 德兴市| 景洪市| 彭水| 宁武县| 清水河县|