2011-03-21 106 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

相关问题