2011-03-21 134 views
1

如果我有字段本身,是否可以通過Java反射來獲取字段?這是一個原始的浮動(公共的,沒問題)。我不想用它的名字作爲String。通過反射獲取Java字段,但不是通過字符串名稱獲取Java字段

實施例:

public class TVset { 
    public float voltageA; 
    public float voltageB; 
    public float voltageC; 
    public TVset(...) {...} // constructor 
    public void function() {...} // it changes voltages 
} 

class Voltmeter{ 
    Object theObject; 
    Field theField; 

    Voltmeter(Object obj) { 
    theObject = obj; 
    Class theFieldClass = obj.getClass(); 
    Class theContainerClass = theFieldClass.getDeclaringClass(); 
    Field theField = ??? // <-- here I don't want to use a String 
    } 

    float getVoltage() { 
    return theField.getFloat(theObject); 
    } 
} 

TVset tv1 = new TVset(...); 
TVset tv2 = new TVset(...); 

Voltmeter meter = new Voltmeter(tv1.voltageB); 
meter.getVoltage(); 
tv1.function(); 
meter.getVoltage(); <- should reflect the changed voltage 
tv1.function(); 
meter.getVoltage(); <- should reflect the changed voltage 
... 

的效果類似於通過引用傳遞浮子,但沒有包成一個包裝類。

我需要衡量不同的電視機不同的電壓,只是通過改變線路:

Voltmeter meter = new Voltmeter(tv1.voltageB); 

別的東西,如:

Voltmeter meter = new Voltmeter(tv2.voltageA); 

是否有可能與反思辦呢?

Thx

+0

你能否詳細說一下「我不想用字符串」? – BalusC 2011-03-21 21:35:54

+0

我剛剛發現編寫新的電壓表(tv2,「voltageA」)很難看,因爲我確切知道TVset中的哪些字段,並且我可以編寫新的(tv2.voltageA)。另外,如果我無意中編寫了新的(tv2.vltageA),編譯器會在運行之前對我大吼一聲。 – Amenhotep 2011-03-21 21:47:54

回答

2

要使用反射你必須使用一個字符串。而不是使用浮點數,你可以使用一個對象來包裝可變浮點數或簡單的浮點數[1];

順便說一句,除非你有一個很好的理由,否則我不會使用float,double遭受的舍入誤差要小得多。

public class TVset { 
    public double[] voltageA = { 0.0 }; 
    public double[] voltageB = { 0.0 }; 
    public double[] voltageC = { 0.0 }; 
} 

class Voltmeter{ 
    final double[] theField; 

    Voltmeter(double[] theField) { 
    this.theField = theField; 
    } 

    double getVoltage() { 
    return theField[0]; 
    } 
} 
// works just fine. 
Voltmeter meter = new Voltmeter(tv1.voltageB); 

編輯:使用抽象訪問器。這是做到這一點的最快方法。 AFAIK,差距小於10納秒。

public abstract class Voltmeter{ // or use an interface 
    public abstract double get(); 
    public abstract void set(double voltage); 
} 

public class TVset { 
    private double _voltageA = 0.0; 
    private double _voltageB = 0.0; 
    private double _voltageC = 0.0; 
    public final Voltmeter voltageA = new Voltmeter() { 
    public double get() { return _voltageA; } 
    public void set(double voltage) { _voltageA = voltage; } 
    } 
    public final Voltmeter voltageB = new Voltmeter() { 
    public double get() { return _voltageB; } 
    public void set(double voltage) { _voltageB = voltage; } 
    } 
    public final Voltmeter voltageC = new Voltmeter() { 
    public double get() { return _voltageC; } 
    public void set(double voltage) { _voltageC = voltage; } 
    } 
} 

就個人而言,如果速度很關鍵,我會直接按名稱使用字段。你不會變得更簡單或更快。

+0

但是這不會引入性能處罰嗎? TVset對象需要每秒進行數百萬次電壓更新。這就是爲什麼我使用原始浮點數(精度不是問題)。 – Amenhotep 2011-03-21 21:40:19

+0

有一個很小的懲罰。它比使用反射小得多。如果您願意,您可以每秒完成1億次更新。 – 2011-03-21 22:16:34

+1

如果你想避免使用數組,你可以使用抽象的訪問器類。它不那麼優雅,但更高效。 – 2011-03-21 22:18:35

0

如果您控制TVSet但由於某種原因需要使用反射,避免錯誤的一種好方法是在TVSet類中編寫您需要的方法/字段名作爲字符串常量。

但是,如果您關心的是性能,反思不是要走的路,因爲通過反射訪問字段或方法可能比通過getter或直接訪問要慢得多。

2

爲了完整起見,我已經包含了解決這個問題的委託方式。我也不建議讓你的花車與公共訪問。

public class stackoverflow_5383947 { 

    public static class Tvset { 

     public float voltageA; 
     public float voltageB; 
     public float voltageC; 

     public Tvset() { 
     } 

     public void function() { 
      voltageA++; 
     } 
    }; 

    public static class Voltmeter { 

     private VoltageDelegate _delegate; 

     public Voltmeter(VoltageDelegate delegate) { 
      _delegate = delegate; 
     } 

     float getVoltage() { 
      return _delegate.getVoltage(); 
     } 
    }; 

    public static interface VoltageDelegate { 

     public float getVoltage(); 
    } 

    public static void main(String[] args) { 
     final Tvset tv1 = new Tvset(); 
     Voltmeter meter = new Voltmeter(new VoltageDelegate() { 
      public float getVoltage() { 
       return tv1.voltageA; 
      } 
     }); 

     System.out.println(meter.getVoltage()); 
     tv1.function(); 
     System.out.println(meter.getVoltage()); 
     tv1.function(); 
     System.out.println(meter.getVoltage()); 
    } 
} 
+0

唉,如果我剛剛2秒前發佈......;) – 2011-03-21 22:42:43

+0

我明白了。 「新電壓表」的東西看起來不像我想要的那麼漂亮,但我想它非常高效。謝謝。 – Amenhotep 2011-03-21 22:50:07

+0

噢,這是「抽象訪問器類」?涼! :o) – Amenhotep 2011-03-21 22:51:38

0

在這裏你可以給你的float值而不是字符串。

class Voltmeter{ 
    Object container; 
    Field theField; 

    Voltmeter(Object obj, float currentValue) { 
    container = obj; 
    Class<?> containerClass = obj.getClass(); 
    Field[] fields = containerClass.getFields(); 
    for(Field f : fields) { 
     if (f.getType() == float.class && 
      f.getFloat(container) == currentValue) { 
      this.theField = f; 
      break; 
     } 
    } 
    } 

    float getVoltage() { 
    return theField.getFloat(container); 
    } 
} 

然後調用它像這樣:

Voltmeter meter = new Voltmeter(tv1, tv1.voltageB); 

它的工作原理只有在電壓表創建時的電壓是不同的(而不是NAN),因爲它需要在第一場與正確的價值。我認爲這並不是真的更有效率。

我不會推薦這個。

+0

如果我真的需要反思,我必須同意這將是解決方案。但事實證明,對於我的問題還有其他更有效的解決方案。有人說......不完美。 :o)Thx。 – Amenhotep 2011-03-21 23:02:31

+0

@Amenhotep:即使使用反射,最好只獲取一次Field對象,然後將其提供給單獨的Voltmeter構造函數,而不是通過其值查找字段。 – 2011-03-21 23:11:26

相關問題