2012-01-16 51 views
4

此代碼用於對列表進行排序。該列表可能包含數千個元素但少於10k。我被建議不要在這裏使用反射......爲什麼不呢?

protected <E> int compareFields(E o1, E o2, String fieldName){ 
    try { 
     Comparable o1Data = (Comparable) o1.getClass().getMethod(fieldName).invoke(o1); 
     Comparable o2Data = (Comparable) o2.getClass().getMethod(fieldName).invoke(o2); 
     return o1Data == null ? o2Data == null ? 0 : 1 : 
       o2Data == null ? -1 : o1Data.compareTo(o2Data); 
    } catch(Exception e) { 
     throw new RuntimeException(e); 
    } 
} 

有人勸我

這樣!! 要麼用合適的比較,或者提取相關性的方法提供方法「請不要用的東西反射(可能以原始類型不支持的方式進行計算)或兩者兼有。「

更好的方式來做到這將是很好的一個例子。

語境: 我有與數據表許多屏幕。每一個都是從List中構建的。每個數據表需要按其6列中的每一列進行排序。這些列是Date或String。

+1

什麼是上下文?排序數據集? – 2012-01-16 19:25:36

+0

@Thomas Jungblut是的,我正在排序,名單可能在1000年。 – Dale 2012-01-16 19:27:04

+8

那麼發佈的評論已經告訴你該做什麼。我完全同意:如果你可以改變代碼(筆記的作者似乎也假設這一點),那麼通過反射來做這件事不僅是低效但可怕的代碼來維護(並且非常脆弱)。 – Voo 2012-01-16 19:29:42

回答

4

使用反射這裏將可能要慢得多,因爲你是通過使用getClassgetMethodinvoke而不是使用對象的原生比較方法加入堆棧幀到每個比較的數目。

理想情況下,你會寫,以避免在簽名中使用的object的方法。一個「合適的比較器」至少會強烈地綁定到對象的類型(你認爲它是相同的)。如果您必須有動態字段比較(如其出現),那麼至少反射可以封裝在該比較器中。

如果你打算把這種上千次,不過,這將是最好預先綁定一個比較,以你被分揀場。這樣,您只需要預先撥打getMethod,而不是每個單獨的比較一次。

+0

OP正在比較對象的屬性,它們是「Comparable」。如果需要按照一個以上的標準對它們進行分類,那麼對象本身是否實現「Comparable」無關緊要。這個想法可能允許動態排序,例如在數據網格中。 – Groo 2012-01-16 19:32:51

+0

反映可能也必須做一些安全檢查和什麼。特別是在較老的JVM上,反射總體上非常緩慢,而且它變得越來越好,但它仍然很難對JIT進行優化(例如推測不是內聯)。所以肯定是比一點慢一點。 – Voo 2012-01-16 19:33:11

+0

@格羅,謝謝,相應更新。 – harpo 2012-01-16 19:37:42

1

很難給出一個很好的例子,沒有上下文,所以現在這裏就是爲什麼它不是最好的主意,一個小清單:

  1. 提供的字段沒有任何的是類似的擔保(不知道爲什麼代碼這裏需要抓住這個例外並重新命名它)。
  2. 如果提供什麼對象的類型並不意味着以這種方式進行比較? (這是一個過於通用的方法名稱,知道它應該如何使用)。
  3. 它沒有強類型。將字段名稱設置爲字符串意味着只要屬性名稱發生更改,就必須在各處更改代碼,並且很難找到需要進行這些更改的位置。
  4. 反射比以強類型方式實現時可能慢。
1

其他答案很好地描述了爲什麼不建議使用反射。我想添加一個使用更傳統的解決方案的例子。

而不是指定用於比較兩個對象的字段,您應該將Comparator實例作爲參數。這樣使用此方法的客戶端可以指定如何比較這兩個對象。

protected <E> int compareFields(E o1, E o2, Comparator<E> comparator) { 
    return comparator.compare(o1, o2); 
} 

和實例調用這個函數應該是這樣的:

MyClass a = ...; 
MyClass b = ...; 
Comparator<MyClass> intFieldComparator = new Comparator<MyClass> { 
    public int compare(MyClass o1, MyClass o2) { 
     int field1 = o1.getIntField(); 
     int field2 = o2.getIntField(); 

     return field2 - field1; 
    } 
}; 

compareFields(a, b, intFieldComparator); 

如果要比較使用多個字段對象可以定義不同的比較。

相關問題