2016-10-04 85 views
0

我已經給出了一個包含200個字段的類,在這些字段中使用反射來讀取它們的值。它基本上是這樣的一種獲取字段值而不使用反射的方法

for (Field f : this.getClass().getFields()) 
     { 
      try 
      { 
       Object o = f.get(this); 

       if (f.getType() == String.class) 
       { 
        //do things with the string 
       } 
      } 
      catch (Exception ex) 
      { 
       logger.error("Cannot get value for field. {}", ex.getMessage()); 
      } 

     } 

這非常適用於領域的這樣一個笨重的量我認爲是反射點。我被要求重構它,因爲它很慢(是嗎?)。

到目前爲止,我唯一可以想出的方法是用不合要求的硬編碼,還有另一種快捷方法嗎?

+1

我投票結束這個問題,因爲OP有一個工作代碼,並要求重構。請查看[問]並考慮在[codereview.se]上提出這個問題。 – xenteros

+0

更好,把整個班。 「慢」 - 這取決於班級的使用情況和內容。就我個人而言,我認爲這裏的反思是最好的解決方案......如果你想保存相同的邏輯。看起來這是一個抽象失敗(一個類中200個字段的混亂需要處理和過濾很多次),而不是一個嚴重的實現缺陷。 – Les

+0

速度慢嗎?你告訴我。在你的程序中加入一個分析器,看看它在這個循環中花費了多少時間。 –

回答

4

首先,您應該使用探查器驗證確實速度很慢。反射比正常訪問變量慢,但這並不一定意味着它是緩慢的來源。

假設您使用setter來修改這些值,則只要調用setter,就可以重構該類以更新Map<String,Object>。這提供了比反射更快的訪問字段,但根據您的使用情況可能無法實現。

+0

啊,非常好。可悲的是,這些田地是公共的,並且直接設置。 – Nanor

+1

@Nanor一次安裝程序將是有用的...! – Kayaman

3

大部分時間都花在獲取Field對象上(可能會過濾它們)實際的查找速度可能非常快。我使用ClassValue來緩存這些信息並加快速度。

public enum StringFields { 
    INSTANCE; 

    final ClassValue<List<Field>> fieldsCache = new ClassValue<List<Field>>() { 
     @Override 
     protected List<Field> computeValue(Class<?> type) { 
      return Collections.unmodifiableList(
        Stream.of(type.getFields()) 
          .filter(f -> f.getType() == String.class) 
          .peek(f -> f.setAccessible(true)) // turn off security check 
          .collect(Collectors.toList())); 
     } 
    }; 

    public static List<Field> getAllStringFields(Class<?> type) { 
     return INSTANCE.fieldsCache.get(type); 
    } 
} 
+0

所以,如果我知道字段的名稱,我可以做'Object.get(String)',它會更快? – Nanor

+0

@Nanor如果你有Field對象緩存它會更快。將添加一個例子,但繁忙的ATM –

1

迄今爲止唯一的方法,我可以拿出他的硬編碼的不敬虔的量,有另一種快速的方法?

您可以使用反射來獲取這些字段的獲取者並生成讀出這些獲取者的代碼。

代碼生成可以成爲構建步驟的一部分。