2014-05-02 58 views
-1

公共變量我有一些變量:改變從一個方法

float firstFloatSize = 0.0; 
float secondFloatSize = 1.0; 
float thirdFloatSize = 2.0; 
float fourthFloatSize = 3.0; 

我想從一個方法,它會收到名稱和變量作爲參數的新值來更改這些變量。像這樣:

public void changeValue("firstFloatSize", 3.0); 

如果我運行了,我會將變量「firstFloatSize」的值更改爲3.0。

這會有點可能嗎?我知道我可以創建一個浮動包裝類,並在該類中實現了這樣的方法,但我只是好奇,如果我能以另一種方式實現這一點。

+4

這聽起來含糊地反映相關,這意味着不,你不能。 (更具體地說,你可以,但不應該沒有很好的理由) – awksp

+0

爲什麼你不想使用getters和setter? – Oyeme

+0

你嘗試過使用Map 嗎? –

回答

0

可能這樣做使用反射,但它會創建將難以維護的代碼。例如,更改變量名稱會破壞反射代碼:直到運行時纔會注意到這一點。你也可以繞過封裝(可能是因爲你注意到成員數據是公開的)。

我建議你以正常的方式做,並設置和獲取方法。

1

使用setProperty從apache的共同PropertyUtils

PropertyUtils.setProperty(this,"firstFloatSize", 3.0); 
+0

這仍然在內部使用反射,這可能是令人反感的... – awksp

+1

user3580294:對不舒服反射的人的其他簡單方法之一。 – suren

+0

只要字段名稱發生更改,這仍會自動打破。 – hiergiltdiestfu

0

如果這些字段的主要歧視性點是「第一」,「第二」等,則可以使用一個數組來存儲值,UND設置根據該陣列中的索引而改變的值的方法:

float[] floatSizes = new float[]{ 0, 1, 2, 3 }; 

public void changeValueAtPosition(int index, float newValue){ 
    floatSizes[index] = newValue; 
} 

當然本實施例缺少一些常見警衛的參數(如確保指數是有效的),並且可以通過使用能夠提高標準類型(如en嗯)而不是原始的int來切換你想改變的值。然後

更改「firstFloatSize」將通過調用changeValueAtPosition(0, 3);

重申其他答案點是可能的:如果有其他的,更簡單的方法不使用反思。基於反射的代碼是任何大於100 LOC的項目的維護夢魘。

0

您有兩種基本選擇:

要麼編寫自定義的調度方法:

public void changeValue(String fieldName, float newValue) 
{ 
    // Java 6 style: 
    if("firstFloatSize".equals(fieldName)) { 
     targetClass.firstFloatSize = newValue; 
    } else if("secondFloatSize".equals(fieldName)) { 
     targetClass.secondFloatSize = newValue; 
    } else if // ... and so on 

    // or, alternatively, Java 7 style: 
    switch(fieldName) 
    { 
     case "firstFloatSize": targetClass.firstFloatSize = newValue; break; 
     case "secondFloatSize": targetClass.secondFloatSize = newValue; break; 
     // ... and so on 
    } 
} 

或者使用反射:

public void changeValue(String fieldName, float newValue) 
{ 
    try 
    { 
    Field field = targetObject.getClass().getField(fieldName); 
    field.setFloat(targetObject, newValue); 
    } 
    catch(...) { ... } 
} 

我不知道,如果你的花車以場同一班或另一班。如果是同一班,顯然不需要targetObject。否則,當然,您需要將targetObject替換爲所需對象的引用。

請注意,這兩種方式都不是很好,因爲其他評論已經說明。兩者都不是很好維護,例如,如果您希望將來重命名其中一個浮點數,則必須手動檢查所有出現的字符串,因爲在這些情況下,編譯器無法確定正確性。另外(儘管這很明顯),如果你有多個你想要訪問的相似的浮點數,你也可以創建一個數組並使用一個索引(可能由一個枚舉支持)而不是一個字符串解決它們。但是這與原來的問題相去甚遠,所以我在此不再詳述...

+1

從Java 7開始,if-cascade也可以通過切換字符串字面值來完成,其中 - 恕我直言 - 看起來更優雅,更少混亂。 – hiergiltdiestfu

+0

好點。我修改了我的答案。 –

+0

'getField(fieldName)'不會返回專用字段,您最終將使用'java.lang.NoSuchFieldException'使用'.getDeclaredField(name)'代替。 –

0

我推薦使用第三方庫。

但是如果你想使用Java API的原料,下面是一個示例代碼..

public class ReflectionSample { 

    private float value1 = 1.0f; 

    public float getValue1() { 
      return this.value1; 
    } 

    public void changeValue(String fieldName, float value) throws Exception { 
      Field field = this.getClass().getDeclaredField(fieldName); 
      boolean accessible = field.isAccessible(); 
      field.setAccessible(true); 
      field.set(this, value); 
      field.setAccessible(accessible); 
    } 

    public static void main(String[] args) throws Exception { 
      ReflectionSample sample = new ReflectionSample(); 
      sample.changeValue("value1", 3.0f); 
      System.out.println(sample.getValue1()); 
    } 
} 
0

作爲一個良好的編碼習慣。

  1. 你不應該在你的類中有公共變量。
  2. 變量應該是私有的,並具有適當的get和set方法。這是基本的面向對象原則之一。封裝。

但是回到你的代碼。
首先,您如何定義浮點變量存在一個小問題。這些應該是

float firstFloatSize = 0.0f; 

現在有幾種方法可以實現這一點。

  1. 編寫自己的基於反射的代碼。
  2. 使用如下所示的條件代碼。
  3. 使用Apache PropertyUtils。其中使用反射設置您的財產。

仍然最後你的調用代碼應該調用一個適當的設置方法。希望能幫助到你。

public void changeValue(String property, float value) { if(property.equals("firstFloatSize")) { firstFloatSize = value; } else if(property.equals("secondFloatSize")) { secondFloatSize = value; } else if(property.equals("thirdFloatSize")) { thirdFloatSize = value; } else { fourthFloatSize = value; } }

0

不知道正是你需要的設定值,這樣一來,但是這是我想出了無反思:

public class PropertySetter { 

    private float valOne; 
    private float valTwo; 
    private float valThree; 
    private float valFour; 

    public void setValue(FIELDS name, float value) { 
     switch (name) { 
      case valOne: 
       valOne = value; 
       break; 
      case valTwo: 
       valTwo = value; 
       break; 
      case valThree: 
       valThree = value; 
       break; 
      case valFour: 
       valFour = value; 
       break; 
      default: 
       throw new AssertionError(name.name()); 
     } 
    } 

    public enum FIELDS { 

     valOne, 
     valTwo, 
     valThree, 
     valFour; 
    } 
} 

但是如果反射被允許的話,我會做到這一點:

public class ReflectionSetter { 

    private float valOne; 
    private float valTwo; 
    private float valThree; 
    private float valFour; 

    public boolean setValue(String name, float value) { 
     Field[] fields = this.getClass().getDeclaredFields(); 
     for (Field f : fields) { 
      if (f.getName().equals(name)) { 
       try { 
        f.setFloat(this, value); 
       } catch (IllegalArgumentException | IllegalAccessException ex) { 
        Logger.getLogger(ReflectionSetter.class.getName()).log(Level.SEVERE, null, ex); 
       } 
       return true; 
      } 
     } 
     return false; 
    } 
} 

第一種方法有點難以維護,因爲這個類的重構將是一場噩夢。 第二種方式非常好,因爲你只需要知道字段名。