JDK5 新特性


 JDK5新特性目錄導航:

  • 自動拆裝箱
  • Foreach
  • 靜態導入
  • 可變參數 Var args
  • 枚舉
  • 格式化輸出
  • 泛型
  • ProcessBuilder
  • 內省
  • 線程並發庫(JUC)
  • 監控和管理虛擬機
  • 元數據

自動拆裝箱

Java數據類型分兩種:基本數據類型 和  引用數據類型(對象)

有時候我們需要將基本數據類型包裝為對象進行處理

在JKD5以前我們的處理方式:

//int 轉換為 Integer
int i = 10;
Integer integer = new Integer(i);

//Integer 轉換為 int
Integer integer1 = new Integer(100);
int i1 = integer1.intValue();

自動拆裝箱處理方式:

//int 轉換為 Integer
Integer integer = 10;

//Integer 轉換為 int
int i = integer;

將class反編譯可以看出自動拆裝箱的代碼如下:

Integer integer = Integer.valueOf(10);
int i = integer.intValue();

以上就是自動拆裝箱的效果,同理其余基本類型也可以自動裁裝箱對應的對象。詳細對應關系如下表:

基本數據類型 封裝類
int Integer
byte Byte
short Short
long Long
char Character
double Double
float Float
boolean Boolean

 

Foreach

增強for循環,新增一種循環語法,格式:for( : ) 

 

普通for與增強for循環對比如下:

List<String> list = new ArrayList<String>();
list.add("111");
list.add("222");
list.add("333");

//JDK5 以前循環需要定義下標“index”並初始化,判斷是否小於集合長度並自增,循環體還需要賦值
for (int index = 0; index < list.size(); index++ ) {
    String str = list.get(index);
    System.out.println("str: " + str);
}

//foreach 增強for循環只需要下面代碼即可完成上面的操作。
for (String str : list){
    System.out.println("str:" + str);
}

反編譯class文件可以看到增強for循環會被編譯器自動處理如下代碼:

Iterator var4 = list.iterator();

while(var4.hasNext()) {
    str = (String)var4.next();
    System.out.println("str:" + str);
}

具體編譯成什么類型還的根據循環數據實際的數據類型,例如:

//int數組 foreach 
int[] ints = new int[]{1, 2, 3, 4, 5};
for(int i : ints){
    System.out.println("i: " + i);
}

//class反編譯結果
int[] ints = new int[]{1, 2, 3, 4, 5};
int[] var9 = ints;
int var4 = ints.length;

for(int var5 = 0; var5 < var4; ++var5) {
    int i = var9[var5];
    System.out.println("i: " + i);
}

從上面代碼可以大致了解foreach,它基本可以替換掉你所有用普通for循環的代碼

 

靜態導入

靜態導入可以將靜態方法和靜態變量通過 import static 和導包一樣的方式直接導入,使用的時候無需使用類名即可直接訪問。

 1 import static java.lang.System.out;
 2 import static java.lang.Math.*;
 3 
 4 public class ImportStaticTest {
 5 
 6     public static void main(String[] args) {
 7         /*
 8          *  使用靜態導入 import static java.lang.System.out;
 9          *  out.println 可以直接使用調用 而不再需要類System對象去調用
10          *  同時也支持*通配符
11          */
12         out.println("max(3,5): " + max(3,5));
13         out.println("random(): " + random());
14     }
15 }

輸出結果:

max(3,5): 5
random(): 0.7808341266194762

 

可變參數 Var args

當傳入到方法的參數不固定時,就可以使用可變參數 格式:數據類型... 參數名

 

 1 public class VarArgsTest {
 2 
 3     // Tips: 和以往main方式不一樣,一般這樣寫 public static void main(String[] args)
 4     public static void main(String... args) {
 5         varArgs(1);
 6         varArgs(2,3);
 7 
 8         // ...
 9 
10         varArgs(7,8,9,10,11);
11     }
12 
13     // 可變參數的格式: 數據類型... 參數名
14     public static void varArgs(int... ints) {
15         for (int i : ints){
16             System.out.println(i);
17         }
18     }
19 }

輸出結果:

1
2
3
7
8
9
10
11

  

枚舉

關鍵字enum表示枚舉類型,它的作用相當於類聲明中的class關鍵字,

注意事項:

1.不能含有public修飾的構造器,即構造器只能是private修飾,如果沒有構造器編譯器同樣也會自動生成一個帶private修飾無參默認構造器。;

2.所有的枚舉值默認都是public static final 修飾的;

3.枚舉值與值之間用逗號分割,最后一個用分號,如果枚舉值后面沒有任何東西該分號可以省略;

4.每一個枚舉值就是一個枚舉類型的實例;

5.枚舉類型中可以定義帶任意修飾符的非枚舉值變量;

6.枚舉值必須位於枚舉類型的第一位置,即非枚舉值必須位於枚舉值之后;

7.枚舉類型自帶兩個方法,values() 和 value(String name) 兩個方法。

枚舉代碼示例:

 

//定義枚舉類型
public enum SexEnum {
    MAN,WOMAN
}

 

class反編譯結果:

public enum SexEnum {
    MAN,
    WOMAN;

    private SexEnum() {
    }
}

枚舉類型方法默認方法示例:

 1 public class Test {
 2     public static void main(String[] args) {
 3 
 4         SexEnum man = SexEnum.valueOf("MAN");
 5         System.out.println("man: " + man);
 6         SexEnum woman = SexEnum.valueOf("WOMAN");
 7         System.out.println("woman: " + woman);
 8 
 9         SexEnum[] sexEnums = SexEnum.values();
10         for (SexEnum sex : sexEnums) {
11             System.out.println("SexEnum: " + sex);
12         }
13     }
14 }

輸出結果:

man: MAN
woman: WOMAN
SexEnum: MAN
SexEnum: WOMAN

  

格式化輸出

JDK5推出了printf-style格式字符串的解釋器 java.util.Formatter 工具類,和C語言的printf()有些類似。

簡單示例:

//創建對象時指定將結果輸出到控制台
Formatter formatter = new Formatter(System.out);
formatter.format("x = %d , y = %s\n",1 , "test");
formatter.close();

輸出結果:

x = 1 , y = test

Formatter類可以將一些特定風格的字符轉換為另一種格式進行輸出,給出一下常用格式轉換。

d 整數型
s String
f 浮點數
c Unicode字符
b 布爾值
e 科學計數
x 整數(16進制)
h 散列碼(16進制)

 

System.out.printf 和 System.out.foramt 方法的格式化輸出就是調用了Formatter工具類。其中System.out.printf 的源碼實際就是調用用了System.out.foramt方法。

System.out.printf 源碼如下:

public PrintStream printf(String format, Object ... args) {
      return format(format, args);
}

 

泛型

泛型格式:<>

JDK5引入泛型是一個很大的功能增強,使用也比較廣泛。使用多態進行數據傳輸時,JDK5之前使用Object傳輸,然后進行向下轉型,這里可能在運行期強轉失敗拋ClassCastException異常,導致程序異常終止。引入泛型可以將此運行期異常轉移到編譯異常,在編寫代碼時就可以檢測出問題。

import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args) {

        //此處只能在運行期報ClassCastException異常。
        Object obj = new String();
        Integer i = (Integer) obj;

        //泛型
        List<String> list = new ArrayList<String>();
        list.add("abc");
        list.add("efg");
        //此處編譯不通過,類型檢測不能通過,在編譯期就能解決錯誤。
//        list.add(1);
//        list.add(false);
//        list.add(0.5);

    }
}

 

泛型關鍵技術:

1.通配符問號(?)表示任意類型.如"List<?>"表示可以存放任意對象類型的List,和List<Object>一樣。

2.通配符可以連接限制符:extends 和 super

如:上邊界List<? extends Parent> 申明的List只能存放Parent及其子類,而下邊界 List<? super Child> 申明的List只能存放Child及其父類。

3.通用類型,通常使用一個大寫字母表示如:T(這里可以使用任意符合命名規則的字符都可以,不過我通常喜歡使用一個大寫字母表示),它能代表任何類型。

如果使用通用類型申明一個變量,那么必須在類申明后面加上<T>,尖括號里面的符號必須是前面申明的通用類型變量,如果有多個可以使用逗號分割如:<T,D>;

如果使用通用類型申明一個方法返回值或者方法參數,要么如上在類申明后加使用<>申明通用類型,要么在方法前申明通用類型。

 

 1 //在類申明后申明通用類型T,則可以在變量、方法返回值和方法參數使用
 2 public class Test<T> {
 3 
 4     //在變量處使用通用類型,且並需在類申明后申明通用類型
 5     T t;
 6     //此處報錯因為,變量通用類型必須在類申明后申明
 7 //  E e;
 8 
 9     //在方法返回值處使用通用類型
10     public T getT() {
11         return t;
12     }
13 
14     //在方法參數使用通用類型
15     public String getType(T t) {
16         return t.getClass().getSimpleName();
17     }
18 
19     //方法返回值通用類型 和 方法參數通用類型 可以在方法前申明
20     public <E> E getE(E e) {
21         return e;
22     }
23 }

 

ProcessBuilder

 ProcessBuilder可以用來創建操作系統進程,它的每一個實例管理着Process集合,start()方法可以創建一個新的Process實例

主要方法:

1.ProcessBuilder的start()方法:執行命令並返回一個Process對象;

2.ProcessBuilder的environment()方法:返回運行進程的環境變量Map<String,String>集合;

3.ProcessBuilder的directory()方法:返回工作目錄;

4.Process的getInputStream()方法:獲得進程的標准輸出流;

5.Process的getErrorStream()方法:獲得進程的錯誤輸出流。

演示代碼

import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

public class Test {
    public static void main(String[] args) {
        //創建進程
        ProcessBuilder processBuilder = new ProcessBuilder("ipconfig","/all");
        //獲取當前進程的環境變量
        Map<String, String> map = processBuilder.environment();
        Process process = null;
        try {
            //執行 ipconfig/all 命令並返回Process對象
            process = processBuilder.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //獲取進程標准輸出流
        InputStream in = process.getInputStream();
        StringBuffer sb = new StringBuffer();
        int readbytes = -1;
        byte[] b = new byte[1024];
        try{
            while((readbytes = in.read(b)) != -1){
                sb.append(new String(b,0,readbytes));
            }
        }catch(IOException e1){
        }finally {
            try{
                in.close();
            }catch (IOException e2){
            }
        }
        System.out.println(sb.toString());

    }
}

 

內省

內省(Introspector) 是Java 語言對 JavaBean 類屬性、事件的一種缺省處理方法。JavaBean是一種特殊的類,主要用於傳遞數據信息,這種類中的方法主要用於訪問私有的字段,且方法名符合某種命名規則。如果在兩個模塊之間傳遞信息,可以將信息封裝進JavaBean中,這種對象稱為“值對象”(Value Object),或“VO”,這些信息儲存在類的私有變量中,通過set()、get()獲得,如下所示:

Person類示例:

public class Person {

    private String name;
    private int age;
    private String address;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

在類Person中有屬性name、age和address。通過 getName/setName來訪問name屬性,getAge/setAge來訪問age屬性,getAddress/setAddress來訪問address屬性,這是我們默認遵循的規則。Java JDK中提供了一套 API用來訪問某個屬性的 getter/setter 方法,這就是內省。

內省類庫:PropertyDescriptor類庫:

PropertyDescriptor類表示JavaBean類通過存儲器導出一個屬性。主要方法:

1.getPropertyType():獲得屬性的class對象;

2.getReadMeth():獲得讀取屬性值的方法,返回Method對象;

3.getWriteMethod():獲得寫入屬性值的方法,返回Method對象;

4.hashCode():獲得對象的哈希值;

5.setReadMethod(Method readMethod):設置讀取屬性值;

6.setWriteMethod(Method writeMethod):設置寫入屬性值。

//創建Person對象,並賦初始值
Person person = new Person();
person.setName("niannianjiuwang");
PropertyDescriptor propertyDescriptor = new PropertyDescriptor("name",Person.class);
//獲得屬性的Class對象
System.out.println("Class: " + propertyDescriptor.getPropertyType().getSimpleName());
Method method = propertyDescriptor.getReadMethod();
System.out.println("Value: " + method.invoke(person));
System.out.println("HashCode: " + propertyDescriptor.hashCode());

 

線程並發庫(JUC)

JDK5提供了線程處理的高級功能,在(java.util.concurrent)包下。包括:

1.線程護斥:Lock 類、ReadWriteLock接口

Lock的方法:

ReadWriteLock的方法:

 2.線程通信:Condition接口

 Condition的方法:

3.線程池:ExecutorService接口

ExecutorService的方法:

4.同步隊列:ArrayBlockingQueue類

 ArrayBlockingQueue的方法:

5.同步集合:ConcurrentHashMap類、CopyOnWriteArrayList類

ConcurrentHashMap相當於一個HashMap集合,但前者是線程安全的,所以性能上比后者略低。

CopyOnWriteArrayList相當於一個ArrayList集合,前者其所有可變操作(add和set等)都是通過對底層的數組進行一次復制來實現,所以代價非常昂貴。

6.線程同步工具:Semaphore類

Semaphore的方法:

 關於JUC的並發庫類容非常的多,這里將不一一列舉。

 

監控和管理虛擬機

在JDK5中使用Bean監控和管理Java虛擬機,java.lang.management.ManagementFactory是管理Bean的工廠類,通過它的get系列方法能夠獲得不同的管理Bean的實例。

ManagementFactory的方法:

詳細講解以下幾個對象:

1.MemoryMXBean:該Bean用於管理Java虛擬機的內存系統,一個Java虛擬機具有一個實例。

2.ClassLoadingMXBean:該Bean用於管理Java虛擬機的類加載系統,一個Java虛擬機具有一個實例。

3.TreadMXBean:該Bean用於管理Java虛擬機的線程系統,一個Java虛擬機具有一個實例。

4.RuntimeMXBean:該Bean用於管理Java虛擬機的線程系統,一個Java虛擬機具有一個實例。

5.OperatingSystemMXBean:該Bean用於管理操作系統,一個Java虛擬機具有一個實例。

6.CompilationMXBean:該Bean用於管理Java虛擬機的編譯系統,一個Java虛擬機具有一個實例。

7.GarbageCollectorMXBean:該Bean用於管理Java虛擬機的垃圾回收系統,一個Java虛擬機具有一個或者多個實例。

演示代碼:

 1 import java.lang.management.*;
 2 import java.util.List;
 3 
 4 public class Test {
 5     public static void main(String[] args){
 6         //Java虛擬機的內存系統
 7         MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
 8         System.out.println("虛擬機的堆內存使用量: " + memoryMXBean.getHeapMemoryUsage());
 9         System.out.println("虛擬機的非堆內存使用量: " + memoryMXBean.getNonHeapMemoryUsage());
10         //Java虛擬機的類加載系統
11         ClassLoadingMXBean classLoadingMXBean = ManagementFactory.getClassLoadingMXBean();
12         System.out.println("當前加載到Java虛擬機中的類的數量: " + classLoadingMXBean.getLoadedClassCount());
13         System.out.println("自Java虛擬機開始執行到目前已經加載的類的總數: " + classLoadingMXBean.getTotalLoadedClassCount());
14         //Java虛擬機的線程系統
15         ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
16         System.out.println("當前線程的總CPU時間: " + threadMXBean.getCurrentThreadCpuTime());
17         System.out.println("當前活動線程的數目,包括守護線程和非守護線程: " + threadMXBean.getThreadCount());
18         //Java虛擬機的線程系統
19         RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
20         System.out.println("當前Java庫路徑: " + runtimeMXBean.getLibraryPath());
21         System.out.println("當前Java虛擬機實現提供商: " + runtimeMXBean.getVmVendor());
22         //操作系統
23         OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
24         System.out.println("當前Java虛擬機可以使用的處理器數目: " + operatingSystemMXBean.getAvailableProcessors());
25         System.out.println("當前操作系統名稱: " + operatingSystemMXBean.getName());
26         //Java虛擬機的編譯系統
27         CompilationMXBean compilationMXBean = ManagementFactory.getCompilationMXBean();
28         System.out.println("當前(JIT)編譯器的名稱: " + compilationMXBean.getName());
29         System.out.println("當前即時(JIT)編譯器的名稱: " + compilationMXBean.getTotalCompilationTime());
30         //Java虛擬機的垃圾回收系統
31         List<GarbageCollectorMXBean> garbageCollectorMXBeanList = ManagementFactory.getGarbageCollectorMXBeans();
32         for (GarbageCollectorMXBean garbageCollectorMXBean : garbageCollectorMXBeanList) {
33             System.out.println("當前垃圾收集器的名字: " + garbageCollectorMXBean.getName());
34             System.out.println("當前垃圾收集器累計回收總次數: " + garbageCollectorMXBean.getCollectionCount());
35             System.out.println("當前垃圾收集器累計回收總時間: " + garbageCollectorMXBean.getCollectionTime());
36         }
37     }
38 }

輸出結果:

虛擬機的堆內存使用量: init = 134217728(131072K) used = 4094288(3998K) committed = 128974848(125952K) max = 1900019712(1855488K)
虛擬機的非堆內存使用量: init = 2555904(2496K) used = 5223536(5101K) committed = 8060928(7872K) max = -1(-1K)
當前加載到Java虛擬機中的類的數量: 586
自Java虛擬機開始執行到目前已經加載的類的總數: 586
當前線程的總CPU時間: 546875000
當前活動線程的數目,包括守護線程和非守護線程: 6
當前Java庫路徑: D:\Program Files\Java\jdk1.8.0_121\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;D:\Program Files (x86)\IDM Computer Solutions\UltraEdit;D:\development\maven\apache-maven-3.5.2\bin;D:\Program Files (x86)\ClockworkMod\Universal Adb Driver;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;D:\Program Files\Git\bin;.
當前Java虛擬機實現提供商: Oracle Corporation
當前Java虛擬機可以使用的處理器數目: 8
當前操作系統名稱: Windows 10
當前(JIT)編譯器的名稱: HotSpot 64-Bit Tiered Compilers
當前即時(JIT)編譯器的名稱: 99
當前垃圾收集器的名字: PS Scavenge
當前垃圾收集器累計回收總次數: 0
當前垃圾收集器累計回收總時間: 0
當前垃圾收集器的名字: PS MarkSweep
當前垃圾收集器累計回收總次數: 0
當前垃圾收集器累計回收總時間: 0

 

元數據

元數據也可以叫注解,這個名字估計容易理解,格式:@注解名

注解的作用范圍,可以通過java.lang.annotation.ElementType查看:

1.TYPE:類、接口(包括注釋類型)或enum聲明

2.FIELD:字段聲明(包括enum常量)

3.METHOD:方法申明

4.PARAMETER:參數申明

5.CONSTRUCTOR:構造器申明

6.LOCAL_VARIABLE:局部變量申明

7.ANNOTATION_TYPE:注解類型申明

8.PACKAGE:包申明

JDK內置三種標准注解: 

@Override: 注解只能使用在方法上,表示當前的方法定義將覆蓋超類中的方法。如果你不小心拼寫錯誤,或者方法簽名對不上被覆蓋的方法,編譯器就會發出錯誤的提示

@Deprecated: 注解可使用在構造器、字段、局部變量、方法、包、類接口以及枚舉上,表示被棄用,不鼓勵使用,編譯器會發出警告信息。通常是因為它是危險的,或則因為有更好的選擇。

@SuppressWarnings:注解可以使用在構造器、字段、局部變量、方法、類接口以及枚舉上,必須指定value值,關閉不當的編譯器警告信息。告訴編譯器不提示某某警告信息。

注意的幾個問題:

1.  當注解的元素沒有默認值的時候,在使用的時候必須為其指定初始值

2.  如果注解元素有了初始值,那么在使用的時候可以為其賦新的值,否則將使用默認值

3.  一個較為特殊的情況:注解元素當且僅當其只有一個元素且名稱為value時,在使用該注解的時候為其賦值時可以不用寫屬性(元素)名稱

元注解:

java內置了4種元注解,元注解負責注解其它的注解,可以理解成java中用來注解Annotation的Annotation

@Retention: 保留策略,表示注解有多長保留,先了解JAVA文件的三個時期:SOURCE 源文件期(*.java文件) -> CLASS 編譯器編譯期(*.class文件) -> RUNTIME jvm運行時期。

@Target: 表示注解使用的上下文,TYPE、FIELD、METHOD、PARAMETER、CONSTRUCTOR、LOCAL_VARIABLE、ANNOTATION_TYPE和PACKAGE。詳細說明返回看注解的作用范圍。

@Documented: 表示將被javadoc記錄。

@Inherited: 表明注釋類型是自動繼承的。如果一個繼承的元注釋出現在注釋類型上聲明,用戶在一個類上查詢注釋類型聲明,類聲明沒有這種類型的注釋,然后該類的超類將自動被查詢注釋類型。這個過程將會重復直到這個注釋類型被找到,或者類層次結構的頂部(對象)是達到了。如果沒有超類有這種類型的注釋,那么查詢將表明的類沒有這樣的注釋。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM