Java 細節彙總(4)

1. Arrays 中的雙軸快排

Jdk 1.7 之後,工具類 Arrays 中的排序方法在排序對象爲基本數據類型的時候會使用雙軸快排,這種排序方法比經典排序更快

public static void sort(int[] a) {
        DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0);
    }

如我們所知,經典快排挑一個數(Pivot)把數組分成兩份,而 Dual-Pivot 其實就是用兩個Pivot,把整個數組分成三份

  • 經典快排核心思想

    接受一個數組,挑一個數(Pivot),把比這個數小的那一攤數放在它的左邊,比它大的那一攤數放在它的右邊,然後再對這個數左右兩攤數遞歸的執行快排過程,直到子數組只剩一個數爲止

我們通常用時間複雜度來衡量一個算法的性能,對於排序算法,時間複雜度的計算依據的是排序導致的元素比較的次數,主要和 CPU 相關。如果按照元素比較次數來比較的話,其實雙軸快排的元素比較次數比經典快排要多,而雙軸快排更快的原因如下,它擁有比經典快排更少的元素掃描動作

  • CPU速度和內存速度的不匹配

    CPU速度遠比內存速度更快,因爲CPU會等待內存傳輸數據,內存牆(Memory Wall)的存在限制了程序運行速度。這種情況下,元素比較次數的多少已經無法完全反映算法優劣,因爲這種比較的方法只考慮了CPU的因素,沒有考慮內存的因素

  • 新的性能衡量標準:掃描元素個數

    爲了解決時間複雜度無法反映算法真實性能的問題,雙軸排序的作者提出了新的衡量標準,即掃描元素個數。這種標準把對於數組裏面一個元素的訪問 array[i] 稱爲一次掃描,對於同一個下標其對應的值不變的話,即使多次讀寫也只算一次掃描。這種標準實際反映的是CPU與內存之間的數據流量的大小,將比較慢的內存的因素也考慮進去了,更能體現算法在當下計算機裏面的性能

參考: https://arxiv.org/pdf/1511.01138.pdf


2. Java 中 switch 支持字符串的原理

一個 switch 的使用示例如下,代碼很簡單,我們無法獲知任何有關於其原理的信息,因爲這些都被隱藏在虛擬機的實現裏

    public static void main(String[] args) {
        String s = "nathan";
        getString(s);
    }
    public static void getString(String s) {
        switch (s) {
            case "good":
                System.out.println("good");
                break;
            case "ok":
                System.out.println("ok");
                break;
            default:
                System.out.println(s);
                break;
        }
    }

編譯以上代碼,使用 IDEA 查看其 class 文件,立馬在其中發現端倪。從反編譯的文件中很明顯可以看到,switch 支持字符串是通過 equals() 和 hashCode() 方法來實現的

仔細看可以發現,進行 switch 的實際是字符串 hashCode() 方法返回的 int 類型哈希值,case 命中後通過 equals() 方法進一步進行安全檢查,以避免哈希碰撞導致的錯誤命中
其實 switch 底層只支持整型數據,比如 byte、short、char(ackii碼是整型)以及int,其他數據類型都是轉換成整型之後再使用的

    public static void main(String[] args) {
        String s = "nathan";
        getString(s);
    }

    public static void getString(String s) {
        byte var2 = -1;
        switch(s.hashCode()) {
        case 3548:
            if (s.equals("ok")) {
                var2 = 1;
            }
            break;
        case 3178685:
            if (s.equals("good")) {
                var2 = 0;
            }
        }

        switch(var2) {
        case 0:
            System.out.println("good");
            break;
        case 1:
            System.out.println("ok");
            break;
        default:
            System.out.println(s);
        }

    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章